题意:
给出未来T天股票的买进、卖出的价格的最大上限问如何获利最大。
题解:
不买不卖 买 卖
dp = max{ dp[i-1][j] , dp[x][y] - (j-y)*APi[i] , dp[x][y] + (y-j)*BPi[i] } .....(1)
x<i-w, 0<j-y<MaxP x<i-w, 0<y-j<MaxP
令pre=i-w-1;
==> dp = max { dp[i-1][j], dp[pre][k] - APi[i]*(j-k) , dp[pre][k] + BPi[i]*(k-j) } ......(2)
为什么能推出这步呢?我们观察第一个dp方程里面有dp[i-1][j] 每次都会和这个比较那么之前的
这个dp[i-1][j]在之前就已经和dp[i-2][t1]比较过了,那么dp[i-2][t1]之前也和dp[i-3][t2]比较
过了,一直递归下去发现,i-w-1之前的就已经都比较过了,那么式子(1)从0——>i-w-1滚动比较就是
多余的。由此得出式子(2)的结论。
==> 以买入为例子:dp + j*dp[pre][k] = dp[pre][k] + k*APi[i]; ......(3)
==> 那么久可以用单调的队列去优化,因为很明显左边的值随着 k 单调递增而递增。
/** 不买不卖 买 卖 dp = max{ dp[i-1][j] , dp[x][y] - (j-y)*APi[i] , dp[x][y] + (y-j)*BPi[i] } .....(1) x<i-w, 0<j-y<MaxP x<i-w, 0<y-j<MaxP 令pre=i-w-1; ==> dp = max { dp[i-1][j], dp[pre][k] - APi[i]*(j-k) , dp[pre][k] + BPi[i]*(k-j) } ......(2) 为什么能推出这步呢?我们观察第一个dp方程里面有dp[i-1][j] 每次都会和这个比较那么之前的 这个dp[i-1][j]在之前就已经和dp[i-2][t1]比较过了,那么dp[i-2][t1]之前也和dp[i-3][t2]比较 过了,一直递归下去发现,i-w-1之前的就已经都比较过了,那么式子(1)从0——>i-w-1滚动比较就是 多余的。由此得出式子(2)的结论。 ==> 以买入为例子:dp + j*dp[pre][k] = dp[pre][k] + k*APi[i]; ......(3) ==> 那么久可以用单调的队列去优化,因为很明显左边的值随着 k 单调递增而递增。 */ #include<iostream> #include<math.h> #include<stdio.h> #include<algorithm> #include<string.h> #include<vector> #include<map> using namespace std; typedef __int64 lld; #define oo 0x3f3f3f3f #define maxn 2005 int dp[maxn][maxn]; struct NODE { int p,s; }q[maxn]; int APi[maxn],ASi[maxn]; int BPi[maxn],BSi[maxn]; int main() { int W,MaxP,T,t,head,tail; NODE temp; scanf("%d",&t); while(t--) { scanf("%d %d %d",&T,&MaxP,&W); for(int i=1;i<=T;i++) scanf("%d %d %d %d",&APi[i],&BPi[i],&ASi[i],&BSi[i]); memset(dp,-0x3f,sizeof dp); for(int i=1;i<=W+1;i++) for(int j=0;j<=ASi[i];j++) dp[i][j]=-APi[i]*j; for(int i=2;i<=T;i++) { for(int j=0;j<=MaxP;j++) dp[i][j]=max(dp[i][j],dp[i-1][j]); int pre=i-W-1; if(pre<=0) continue; head=tail=0; for(int j=0;j<=MaxP;j++) { temp.p=dp[pre][j]+j*APi[i]; temp.s=j; //保证队头出来的是最优,那么如果这个temp比队尾还优,那么队尾应该删除 while(head<tail&&q[tail-1].p<temp.p) tail--; q[tail++]=temp; while(head<tail&&j-q[head].s>ASi[i]) head++; dp[i][j]=max(dp[i][j],q[head].p-j*APi[i]); } head=tail=0; for(int j=MaxP;j>=0;j--) { temp.p=dp[pre][j]+j*BPi[i]; temp.s=j; while(head<tail&&q[tail-1].p<temp.p) tail--; q[tail++]=temp; while(head<tail&&q[head].s-j>BSi[i]) head++; dp[i][j]=max(dp[i][j],q[head].p-j*BPi[i]); } } int ans=0; for(int i=0;i<=MaxP;i++) ans=max(ans,dp[T][i]); printf("%d\n",ans); } return 0; }