单调队列 hdu3401 Trade
来源:互联网 发布:ug轮廓3d倒角编程技巧 编辑:程序博客网 时间:2024/04/30 11:37
传送门:点击打开链接
题意:有种股票,现在知道n天,拥有的股票股数必须<=V,每两次操作时间之差必须大于W。接下来n天,分别是当天股票买和卖的价格,以及买和卖的最大上限。刚开始认为钱是INF的,问最后能赚多少钱。
思路:一道非常好的单调队列优化dp的好题!
首先,dp无非就两种设法,
1.dp[i][j]表示最后一次操作为第i天,已经拥有了j只股票的赚的最大钱数.
2.dp[i][j]前i天里,已经拥有了j只股票的赚的最大钱数.
我们可以发现,如果是第一种设法,方程不好转移,所以我们采用第二种,那么很容易就能列出方程
对于i>=W+2
dp[i][j]=dp[i-1][j]
买股票 dp[i][j]=max(dp[i][j],dp[i-W-1][k]+k*AP[i])-j*AP[i], j-k<=AS[i]
卖股票 dp[i][j]=max(dp[i][j],dp[i-W-1][k]+k*BP[i])-j*BP[i], j-k<=BS[i]
所以,买股票的时候j的循环应该是从小到大,卖股票的时候循环应该是从大到小。
然后我们继续来考虑i>=W+2的时候,对于单调队列添加起点的边界考虑。
买股票的时候,我们把j=0添加到单调队列中,卖股票的时候,我们把j=V添加到单调队列中
对于比较复杂的方程,有时候单纯的用单调队列只记录位置,就会显得有点笨重,这里我是采用了结构体,这样可以使得代码更加清晰,而且方便维护。
这题还有另外一个边界,那就是1<=i<=W+1的情况
dp[i][j]=j<=AS[i]?-j*AP[i]:-INF;
if(i>1) dp[i][j]=max(dp[i][j],dp[i-1][j]);
if(i>1) dp[i][j]=max(dp[i][j],dp[i-1][j]);
这个怎么理解呢,因为当i在这个区间的时候,肯定只能取到某一天。
然后对于j>AS[i]的情况,因为第i天实在买不了j只股票,所以这个状态是达不到的,我们记为-INF
其次就是最容易错的那句if语句,因为我们的dp的意义,并不是以第i天为最后一天操作时的赚的最大钱数,而是前i天!
所以我们应该还要考虑这天不选的情况,所以还应该考虑只从前面的状态转移过来时的情况
总的来说,我觉得这题有几个地方都很适合总结。
一个是dp的两种设法,以后要习惯性的想到,不能死扣一种。
第二个就是关于dp的边界,一定要结合dp的含义想清楚再写,否则很有可能调试不出来。
第三个就是单调队列的初始边界,一般是把第一个状态直接加入进去,然后for循环从第二个状态开始
#include<map>#include<set>#include<cmath>#include<ctime>#include<stack>#include<queue>#include<cstdio>#include<cctype>#include<string>#include<vector>#include<cstring>#include<iostream>#include<algorithm>#include<functional>#define fuck(x) cout<<"["<<x<<"]"#define FIN freopen("input.txt","r",stdin)#define FOUT freopen("output.txt","w+",stdout)using namespace std;typedef long long LL;typedef pair<int, int>PII;const int MX = 2e3 + 5;const int INF = 0x3f3f3f3f;int n, V, W;int dp[MX][MX];int c, r;int AP[MX], BP[MX], AS[MX], BS[MX];void umax(int &a, int b) { a = a > b ? a : b;}struct Data { int id, x; Data() {} Data(int _id, int _x) { id = _id; x = _x; }} Q[MX];int solve() { for(int i = 1; i <= W + 1; i++) { for(int j = 0; j <= V; j++) { dp[i][j] = j <= AS[i] ? -j * AP[i] : -INF; if(i > 1) umax(dp[i][j], dp[i - 1][j]); } } for(int i = W + 2; i <= n; i++) { for(int j = 0; j <= V; j++) { dp[i][j] = dp[i - 1][j]; } c = r = 0; Q[r++] = Data(0, dp[i - W - 1][0]); for(int j = 1; j <= V; j++) { while(c < r && j - Q[c].id > AS[i]) c++; int Max = Q[c].x; umax(dp[i][j], Max - j * AP[i]); Data temp(j, dp[i - W - 1][j] + j * AP[i]); while(c < r && Q[r - 1].x < temp.x) r--; Q[r++] = temp; } c = r = 0; Q[r++] = Data(V, dp[i - W - 1][V] + V * BP[i]); for(int j = V - 1; j >= 0; j--) { while(c < r && Q[c].id - j > BS[i]) c++; int Max = Q[c].x; umax(dp[i][j], Max - j * BP[i]); Data temp(j, dp[i - W - 1][j] + j * BP[i]); while(c < r && Q[r - 1].x < temp.x) r--; Q[r++] = temp; } } return dp[n][0];}int main() { int T; //FIN; scanf("%d", &T); while(T--) { scanf("%d%d%d", &n, &V, &W); for(int i = 1; i <= n; i++) { scanf("%d%d%d%d", &AP[i], &BP[i], &AS[i], &BS[i]); } printf("%d\n", solve()); } return 0;}
0 0
- 单调队列 hdu3401 Trade
- 【DP+单调队列】 hdu3401 Trade
- [单调队列DP] HDU3401 Trade
- Trade-----HDU3401----单调队列优化的DP
- hdu3401 Trade 单调队列优化dp
- [HDU3401]Trade && 单调队列优化DP
- hdu3401 Trade 单调队列优化DP
- hdu3401 Trade [单调队列优化dp]
- hdu3401 Trade(单调队列优化dp)
- 【HDU3401】Trade-单调队列优化DP
- [hdu3401] Trade DP单调队列优化
- HDU3401 Trade (动态规划+单调队列)
- 单调队列 例子:hdu3401 trade(dp加单调队列)
- Hdu3401 Trade(dp 单调队列优化)最详细题解
- HDU3401 单调队列优化DP
- 【HDU3401】Trade
- 【HDU3401】Trade
- 单调队列优化dp [HDU2191][HDU3401][POJ1821]
- HDOJ--1006
- ContentProvider启动时机问题简记
- ZOJ 2358 2481
- HDU 1242 Rescue
- 【Android 进阶(一)】Android MVP框架实现过程
- 单调队列 hdu3401 Trade
- R语言--tapply,sapply(因子和列表的操作)
- IOS中5种传值方式详解(属性、Block代码块、代理、单例、通知)
- javascript脚本从载入浏览器到显示执行的过程解析
- HDU 1048 字符串转化(整行读取函数cin.getline(str,100))
- Python yield 使用浅析
- CocoaPods入门 --小白篇
- CSS动画之硬件加速
- spring-session源码解读-4