【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开始,最大值优先。

 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
",maxx);
58     }
59     return 0;
60 }
View Code
原文地址:https://www.cnblogs.com/kane0526/p/3152837.html