Luogu P1860 新魔法药水
题目大意
具体题面及输入格式戳我!
商店里有\(N\)种药水,每种药水都有一个售价和回收价。
小\(S\) 攒了\(V\)元钱,还会\(M\)种魔法,可以把一些药水合成另一种药水。
他在第一天可以购买药水、使用最多\(K\)次魔法,然后第二天在把手头上的药水出售。
现在小\(S\)希望知道两天之内他最多能够赚多少钱?
样例输入:
\(4\ \ 2\ \ 6\ \ 3\)
\(1\ \ 0\)
\(1\ \ 0\)
\(5\ \ 3\)
\(20\ \ 15\)
\(3\ \ 2\ \ 1\ \ 2\)
\(4\ \ 3\ \ 1\ \ 2\ \ 3\)
样例输出:
\(12\)
样例解释:
先购买两个物品1与物品2,合成得到两个物品3 , 花费4元,使用2次魔法
再购买一个物品1与物品2,与其中一个物品3合并出一个物品4,花费2元,使用1次魔法。
到了第二天,卖出当前手头上的一个物品3与一个物品4,获利 15+3 = 18元。
总共使用了2+1=3次魔法,花费4+2=6元,获利 (15+3)-(4+2) = 12元,为最优方案。
数据范围:\(N\leq 60\) ; \(M\leq 240\) ; \(V\leq 10^3\) ; \(K\leq30\) ;
思路与解法
这么好的题目Luogu上竟然没人做,非常全面的一道\(DP\)题。
注意到物品的合成是可以嵌套进行的(用合成的东西去合成新的东西)。
这个就非常的恶心。
\(Solve_a\)
我们假设现在合成只能有一层,即不能用合并出来的东西去合并新的东西。
那么这就是一道非常简单的二维背包了。 所以我们考虑如何消除嵌套合并的影响。
设\(f[i][j]\)表示使用\(j\)次魔法得到物品\(i\)的最低费用。显然初始\(f[i][0] = price[i]\)
那么发现无法直接转移\(f\),但是对于每一个魔法我们是可以\(DP\)的:
我们枚举一个魔法,设\(r[i][j]\)表示得到这个魔法的前i个原料,使用了j次魔法的最低价格.
那么转移:
\[r[\ i\ ][\ j_1+j_2\ ] = r[i-1][j_1] + f[\ itm[i]\ ][j_2]\]
其中\(itm[i]\)为这个魔法的第\(i\)个原料,\(f\)的含义见上。
转移完后用\(r[i][j]\)更新\(f[i][j+1]\)(把这些原料合成又需要一次魔法)即可。
发现一个问题,\(f\)是我们正在求的东西,但是转移中又出现了\(f\)。
一个最直接的想法就是\(TopSort\)一遍再\(DP\),但是此题数据非常恶心每组数据的合成关系都出现了环。
发现我们最多只需要做\(N\)次,所有的\(f\)就都到位了,所以就做\(N\)遍这个\(DP\)即可。
这个部分的时间复杂度为\(O(NMK^2)\),难点在于想到使用\(r\)数组。
\(Solve_b\)
求出了\(f\)数组,剩下的部分就是一个很简单的二维背包了。
\(g[i][j][k]\)表示前\(i\)个物品,使用了\(j\)元,用了\(k\)次魔法的最大利润。
把每一个\(f[i][r]\)看成一个物体,枚举使用次数\(e\)即可:
\[g[i][j][k] = max(\ g[i-1][\ j-e*f[i][r]\ ][\ k-e*r\ ] + profit(i)*e\ )\]
直接这样转移复杂度过高,使用完全背包问题的状态优化,把状态优化为二维\(g[j][k]\)即可,注意枚举顺序。
这个部分时间复杂度为\(O(NK^2V)\),总时间复杂度为\(O(\ NK^2(M+V)\ )\)。
实现代码:
#include<bits/stdc++.h>
#define RG register
#define IL inline
#define pb push_back
#define ll long long
#define gi(x) scanf("%lld",&x);
#define fp(i,j,k) for(RG ll i = j; i <= k; i ++)
#define INF 1e9+7
using namespace std;
ll f[65][35] , r[65][35] , g[1005][35] ;
ll N , M , V , K , pft[65] , cnt;
ll itm[250][605] , sum[250] , Ans; vector<ll>gp[ 65 ];
IL void Min(RG ll &x,RG ll y){if(x > y)x = y;}
IL void Max(RG ll &x,RG ll y){if(x < y)x = y;}
const ll zr = 0;
IL void DP1(RG int u){
RG ll szz = gp[u].size();
for(RG ll sq = 0; sq < szz; sq ++){
RG ll id = gp[u][sq];
fp(i,0,sum[id])fp(j,0,K)r[i][j] = INF;
r[0][0] = 0;
for(RG ll i = 1; i <= sum[id]; i ++)
for(RG ll j1 = 0; j1 <= K; j1 ++)
for(RG ll j2 = 0; j2 + j1 <= K; j2 ++){
Min( r[i][j1+j2] , r[i-1][j1] + f[ itm[id][i] ][j2] );
}
for(RG ll j = 0; j <= K-1; j ++)
Min(f[u][j+1] , r[sum[id]][j]);
}return;
//f[u][j]: 表示使用j次魔法,得到u物品的最小花费
//r[i][j]: 表示得到此魔法前的前i个原料,使用了j次魔法的最小花费。
}
IL void DP2(){
for(RG ll i = 1; i <= N; i ++)
for(RG ll e = 0; e <= K; e ++) //枚举物品
for(RG ll k = e; k <= K; k ++) //用了多少次魔法
for(RG ll val = f[i][e]; val <= V; val ++) //预估花费
Max(g[val][k],g[val-f[i][e]][k-e] + pft[i] ) , Max(Ans , g[val][k]-val);
// g[i][j][k] 表示前i个物品,花费了j元 ,使用了k次魔法 的最大利润。
return;
}
int main(){
gi(N); gi(M); gi(V); gi(K);
fp(i,0,N)fp(j,0,K)f[i][j] = INF;
for(RG ll i = 1; i <= N; i ++){ gi(f[i][0]); gi(pft[i]);}
for(RG ll i = 1; i <= M; i ++){
RG ll x,y; gi(x); gi(y);
sum[i] = y;
for(RG ll j = 1; j <= y; j ++)gi(itm[i][j]);
gp[x].pb(i);
}
for(RG int i = 1; i <= N; i ++)
for(RG int e = 1; e <= N ; e ++)
DP1(e);
Ans = -INF;
DP2(); cout << max(Ans , zr); return 0;
}
Luogu P1860 新魔法药水的更多相关文章
- 洛谷P1860——新魔法药水
传送门:QAQQAQ 题意:商店里有N种药水,每种药水都有一个售价和回收价.小S攒了V元钱,还会M种魔法,可以把一些药水合成另一种药水.他一天可以使用K次魔法,问他一天最多赚多少钱? N<=60 ...
- [P1860]新魔法药水
题目描述 商店里有N种药水,每种药水都有一个售价和回收价.小S攒了V元钱,还会M种魔法,可以把一些药水合成另一种药水.他一天可以使用K次魔法,问他一天最多赚多少钱? 输入输出格式 输入格式: 第一行四 ...
- 洛谷P1860 新魔法药水
洛谷题目链接 动态规划: 这个题目调了我好久....结果循环变量写错了... 而且题目有个坑!!!只能用开始给你的$v$元买入东西 回归正题: 我们定义状态$ans[i][j]$表示第$i$个物品用了 ...
- [luogu P3787][新创无际夏日公开赛] 冰精冻西瓜 [树状数组][dfs序]
题目背景 盛夏,冰之妖精琪露诺发现了一大片西瓜地,终于可以吃到美味的冻西瓜啦. 题目描述 琪露诺是拥有操纵冷气程度的能力的妖精,一天她发现了一片西瓜地.这里有n个西瓜,由n-1条西瓜蔓连接,形成一个有 ...
- Noip前的大抱佛脚----赛前任务
赛前任务 tags:任务清单 前言 现在xzy太弱了,而且他最近越来越弱了,天天被爆踩,天天被爆踩 题单不会在作业部落发布,所以可(yi)能(ding)会不及时更新 省选前的练习莫名其妙地成为了Noi ...
- NOIP前的刷题记录
因为这几天要加油,懒得每篇都来写题解了,就这里记录一下加上一句话题解好了 P4071 [SDOI2016]排列计数 组合数+错排 loj 6217 扑克牌 暴力背包 P2511 [HAOI2008 ...
- test20190803 夏令营NOIP训练19
60+100+0=160 贪婪大陆 面对蚂蚁们的疯狂进攻,小FF的Tower defence宣告失败--人类被蚂蚁们逼到了Greed Island上的一个海湾.现在,小FF的后方是一望无际的大海, 前 ...
- [Luogu 3258] JLOI2014 松鼠的新家
[Luogu 3258] JLOI2014 松鼠的新家 LCA + 树上差分. 我呢,因为是树剖求的 LCA,预处理了 DFN(DFS 序),于是简化成了序列差分. qwq不讲了不讲了,贴代码. #i ...
- Luogu 魔法学院杯-第二弹(萌新的第一法blog)
虽然有点久远 还是放一下吧. 传送门:https://www.luogu.org/contest/show?tid=754 第一题 沉迷游戏,伤感情 #include <queue> ...
随机推荐
- WPF字典集合类ObservableDictionary
WPF最核心的技术优势之一就是数据绑定.数据绑定,可以通过对数据的操作来更新界面. 数据绑定最经常用到的是ObservableCollection<T> 和 Dictionary<T ...
- js压缩上传图片
初学有不当之处,请多多指点, <body> <div class="cc"> <input type="file" id=&quo ...
- 使用VIM将文件的其中的连续几行注释删除或者给其中的连续几行添加注释
一.使用VIM将文件的其中的连续几行注释删除 1.用VIM打开一个文件,比如打开sshd_config文件,以该文件的下面几行为例: #vim sshd_config 2.此时,按ctrl+v键,使 ...
- jersey2.26+spring5+jpa一步步搭建restful服务
前言 首先,为什么想选择Jersey做restful服务呢?我个人比较喜欢它的插件化设计,可以方便的注入自己的全局处理逻辑.再一个就是可以生成wadl描述文件,供查询服务方法.所以在学习spring的 ...
- CentOS7上安装并配置Nginx、PHP、MySql
一.Nginx 1.安装nginx yum install nginx 2.启动nginx systemctl start nginx 除了systemctl start nginx之外,常用的相关命 ...
- Python实现二分查找
老生常谈的算法了. #!/usr/bin/python # -*- coding:utf-8 -*- # Filename: demo.py # 用python实现二分查找 def binarySea ...
- nyoj913 取石子(十) SG函数 + Nimm博弈
思路: 第一堆:SG = n % 3; 第二堆:无规律,打表即可,用hash比set快很多; 第三堆:SG = n; 第四堆:无规律 第五堆:SG = n % 2; 第六堆:SG = n % (i + ...
- JavaScript的this和作用域
本文主要讨论一下JS的作用域和this关键字.作用域,就是你的方法或者变量可访问的区域,是他们执行的上下文.如果你见过这样的代码: function someFunc() { var _this = ...
- rem是如何自适应的
原文链接:http://caibaojian.com/web-app-rem.html 摘要:rem是相对于根元素<html>,这样就意味着,我们只需要在根元素确定一个px字号,则可以来算 ...
- 【前端】jQuery移动端左滑删除
转载请注明出处:http://www.cnblogs.com/shamoyuu/p/left_slide_menu.html <!doctype html> <html> &l ...