zoukankan      html  css  js  c++  java
  • 【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
  • 相关阅读:
    SQL练习(Navicat premium)
    jmeter Thread Name 后面数字1-1 1-2的意思
    jmeter用Stepping Thread Group 递增并发数
    打开文件提示“已被macos使用“,不用每次都设置一遍
    查看访问网页的接口
    mac常用快捷键
    mac修改hosts保存报错
    文本编辑器
    excel时间戳转化为日期
    jmeter察看结果树左侧的请求名称显示为空 开始时间显示1970-01-01
  • 原文地址:https://www.cnblogs.com/kane0526/p/3152837.html
Copyright © 2011-2022 走看看