【HDU 3401 Trade】 单调队列优化dp
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3401
题目大意:现在要你去炒股,给你每天的开盘价值,每股买入价值为ap,卖出价值为bp,每天最多买as股,最多卖出bs股,并且要求两次买卖必须间隔W天,问你在T天内如何进行炒股操作从而获得最大收益。
解题思路:先吐槽一下,会单调队列但不会dp不行,会dp但不会单调队列也不行!!开始dp动态转移方程倒是写对了,然后算算时间复杂度T*T*Maxp*Maxp,优化不得当,一直以为是dp思路错了,囧。
对于有单调队列参与dp的题,dp方程必须准确先写好,然后再观察可否用单调队列。
dp[i][j]:表示第i天手上持有j股的最大利益。三种决策:
{ -------1、不买不卖 dp[i-1][j]
dp[i][j]=max { -------2、买 dp[r][k]-ap[i]*(j-k) (j>=k,r<=i-w-1)
{ -------3、卖 dp[r][k]+bp[i]*(k-j) (j<=k,r<=i-w-1)
由dp方程可知时间复杂度为T*T*Maxp*Maxp,其实仔细观察可以看出,r其实就等于i-w-1(联系决策1想想为什么),时间复杂度降低一维。
看第二个dp转移方程,dp[i][j]=max(dp[i][j],dp[i-w-1][k]-ap[i]*(j-k)).
dp[i-w-1][k]-ap[i]*(j-k)=(dp[i-w-1][k]+ap[i]*k)-ap[i]*j , 在j固定的情况下(dp[i][j]固定),k变式子值变,我们只需保存变化过程中的最大值即可,很容易想到单调队列。决策三亦是如此。因为要保存最大值,所以买是j从0开始和卖是j从Maxp开始,最大值优先。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include <iostream> 2 #include <cstdio> 3 #include <algorithm> 4 #include <cstring> 5 #include <vector> 6 using namespace std; 7 8 const int maxn=2005; 9 const int oo=0x3fffffff; 10 int ap[maxn], bp[maxn], as[maxn], bs[maxn]; 11 int dp[maxn][maxn]; 12 int W, T, Maxp, n; 13 14 struct node 15 { 16 int num, val; 17 }que[maxn]; 18 19 int main() 20 { 21 cin >> T; 22 while(T--) 23 { 24 cin >> n >> Maxp >> W; 25 for(int i=0; i<=n; i++) 26 for(int j=0; j<=Maxp; j++) dp[i][j]=-oo; 27 for(int i=1; i<=n; i++) scanf("%d%d%d%d",ap+i,bp+i,as+i,bs+i); 28 for(int i=1; i<=n; i++) dp[i][0]=0; 29 for(int i=1; i<=W+1; i++) 30 for(int j=1; j<=as[i]; j++) dp[i][j]=-j*ap[i]; 31 for(int j=1; j<=Maxp; j++) 32 for(int i=2; i<=W+1; i++) 33 dp[i][j]=max(dp[i][j],dp[i-1][j]); 34 for(int i=W+2; i<=n; i++) 35 { 36 int front=0, tail=-1; 37 for(int j=0; j<=Maxp; j++) 38 { 39 dp[i][j]=max(dp[i][j],dp[i-1][j]); 40 while(front<=tail&&que[tail].val<=dp[i-W-1][j]+ap[i]*j) tail--; 41 que[++tail].val=dp[i-W-1][j]+ap[i]*j, que[tail].num=j; 42 while(front<=tail&&j-que[front].num>as[i]) front++; 43 dp[i][j]=max(dp[i][j],que[front].val-ap[i]*j); 44 } 45 front=0, tail=-1; 46 for(int j=Maxp; j>=0; j--) 47 { 48 while(front<=tail&&que[tail].val<=dp[i-W-1][j]+bp[i]*j) tail--; 49 que[++tail].val=dp[i-W-1][j]+bp[i]*j, que[tail].num=j; 50 while(front<=tail&&que[front].num-j>bs[i]) front++; 51 dp[i][j]=max(dp[i][j],que[front].val-bp[i]*j); 52 } 53 } 54 int maxx=0; 55 for(int i=0; i<=Maxp; i++) 56 maxx=max(maxx,dp[n][i]); 57 printf("%d\n",maxx); 58 } 59 return 0; 60 }