【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\n",maxx);

58     }

59     return 0;

60 }
View Code

 

你可能感兴趣的:(HDU)