【题意】告诉你 T 天里,物品的买卖价格,和最多买卖数量,还有 T 天里能买入最多的物品数量,每一次买卖间隔时间必须大于 w+1!
【分析】
1. dp[i][j] 表示前 i 天手里有 j 支股票时所获得的最大收益,因为要间隔 w+1 天才能进行一次买卖,所以前 w+1 天只能进行一个操作,那就是买操作。
2. 关于赋初值问题,合法的状态也有可能为负值的,而且结果要取最大值,所以非法状态要赋值为 -INFS.
3. dp[i][j] = max(dp[i-w-1][x] - (j-x)*AP, dp[i-w-1][y] + (y-j)*BP); 另外还有第 i 天什么都不做的情况此时为 dp[i][j] = max(dp[i][j], dp[i-1][j]).
4. 关于转移方程,时间复杂度是很高的,所以要采取单调队列优化,deq[],pos[] 分别放置窗口里面的最大值以及最大值所在的窗口位置。这里我用了一个结构体的队列直接维护这两个信息!
6.推到队列优化也可以这样做,只考虑买的情况,卖的和它对称。dp[i][j] = max(dp[i-w-1][k]-j*ap[i]+k*ap[i]),移下项变成dp[i][j]+j*ap[i] = max(dp[i-w-1][k]+k*ap[i]),很明显可以把后面维护成一个递减的单调队列,每次取队首元素,使得复杂度降为O(N*P)!
【AC代码】
#include <stdio.h> #include <string.h> #include <iostream> #include <algorithm> using namespace std; const int maxn = 2200; const int unf = -0x3f3f3f3f; int N,P,W,dp[maxn][maxn],ap[maxn],bp[maxn],as[maxn],bs[maxn]; //dp[i][j]代表在第i天拥有j股的最大价值 struct node{ int val,pos; }que[maxn]; int main() { int T; scanf("%d",&T); while(T--){ scanf("%d%d%d",&N,&P,&W); for(int i=1; i<=N; i++){ scanf("%d%d%d%d",&ap[i],&bp[i],&as[i],&bs[i]); } //init. memset(dp,unf,sizeof(dp)); for(int i=1; i<=N; i++){ for(int j=0; j<=min(as[i],P); j++){ dp[i][j] = -ap[i]*j; } } //在第天什么也不做 for(int i=2; i<=N; i++){ for(int j=0; j<=P; j++){ dp[i][j] = max(dp[i][j],dp[i-1][j]); } } //状态转移,维护dp[i][j] int head,tail,pre; for(int i=W+2; i<=N; i++){ pre = i-W-1; head = 0,tail = -1; for(int j=0; j<=P; j++){//only buy dp[i][j] = max(dp[i][j],dp[i-1][j]); node temp; temp.val = dp[pre][j]+j*ap[i]; temp.pos = j; //maintain queue. while(head<=tail && que[tail].val<temp.val) tail--; que[++tail] = temp; while(head<=tail &&(j-que[head].pos)>as[i]) head++; if(head<=tail){ dp[i][j] = max(dp[i][j],que[head].val-j*ap[i]); } } head = 0,tail = -1; for(int j=P; j>=0; j--){//only sell dp[i][j] = max(dp[i][j],dp[i-1][j]); node temp; temp.val = dp[pre][j]+j*bp[i]; temp.pos = j; //maintain queue. while(head<=tail && que[tail].val<temp.val) tail--; que[++tail] = temp; while(head<=tail &&(que[head].pos-j)>bs[i]) head++; if(head<=tail){ dp[i][j] = max(dp[i][j],que[head].val-j*bp[i]); } } } printf("%d\n",dp[N][0]);//在最后一天卖完股票的最大值 } return 0; }