• 【单调队列优化DP】BZOJ1855-[Scoi2010]股票交易


    【题目大意】

      已知第i天的股票买入价为每股APi,第i天的股票卖出价为每股BPi(数据保证对于每个i,都有APi>=BPi),第i天的一次买入至多只能购买ASi股,一次卖出至多只能卖出BSi股。 股票交易所规定在两次交易(某一天的买入或者卖出均算是一次交易)之间,至少要间隔W天,也就是说如果在第i天发生了交易,那么从第i+1天到第i+W天,均不能发生交易。同时,在任何时间,一个人的手里的股票数不能超过MaxP。 在第1天之前,有一大笔钱(可以认为钱的数目无限),没有任何股票,求T天之后最多赚到多少钱?

    【思路】

    f[i][j]表示表示到第i个交易日手中持有至多j股时的最大收益。

    1、从前一天不买不卖:f[i][j]=max(f[i-1][j],f[i][j])

    2、从i-W-1天买股:f[i][j]=max(f[i-W-1][k]-(j-k)*AP[i],f[i][j])

      f[i][j]=max(f[i-W-1][k]+k*AP[i])-j*AP[i]

       令g[i-W-1][k]=f[i-W-1][k]+k*AP[i] → f[i][j]=max(g[i-W-1][k]) - j*AP[i]

    3、从i-W-1天卖股:f[i][j]=max(f[i-W-1][k]+(k-j)*BP[i],f[i][j])

      f[i][j]=max(f[i-W-1][k]+k*BP[i])-j*BP[i]。

          令g'[i-W-1][k]=f[i-W-1][k]+k*BP[i] → f[i][j]=max(g'[i-W-1][k]) - j*BP[i]

    由于对于g[i-W-1][j]与g'[i-W-1][j]均满足:若j1>j2且g[i-W-1][j1]>g[i-W-1][j2],则不必保留g[i-W-1][j2]。所以可以用单调队列来进行优化。

    #关于初始化#f[0][0]=0,对于1~W+1天,仅存在买入操作,初始值为-AP[i]*j。

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #define pre i-W-1
     6 #define INF 0x7fffffff
     7 using namespace std;
     8 const int MAXN=2000+5;
     9 struct node
    10 {
    11     int f,pos;    
    12 };
    13 int T,MaxP,W;
    14 int AP[MAXN],BP[MAXN],AS[MAXN],BS[MAXN];
    15 int f[MAXN][MAXN];//表示到第i个交易日手中持有j股时的最大收益
    16 node q[MAXN];
    17 
    18 void init()
    19 {
    20     scanf("%d%d%d",&T,&MaxP,&W);
    21     for (int i=1;i<=T;i++) scanf("%d%d%d%d",&AP[i],&BP[i],&AS[i],&BS[i]);
    22 }
    23 
    24 void dp()
    25 {
    26     memset(f,128,sizeof(f));
    27     for(int i=0;i<=W+1;i++)
    28     {
    29         for(int j=0;j<=(min(MaxP,AS[i]));j++)
    30             f[i][j]=-AP[i]*j;//表示前(w+1)天仅有可能进行买入操作 
    31     }
    32     f[0][0]=0; 
    33     for (int i=1;i<=T;i++)
    34     {
    35         for (int j=0;j<=MaxP;j++) f[i][j]=max(f[i][j],f[i-1][j]);
    36         if (pre>0)
    37         {
    38             int head=0,tail=0;
    39             for (int j=0;j<=MaxP;j++)
    40             {
    41                 int nowf=f[pre][j]+AP[i]*j;
    42                 while (head<tail && q[tail-1].f<nowf) tail--;
    43                 q[tail++]=(node){nowf,j};
    44                 while (head<tail && q[head].pos<j-AS[i]) head++;
    45                 f[i][j]=max(f[i][j],q[head].f-AP[i]*j);
    46             }
    47             
    48             head=0,tail=0;
    49             for (int j=MaxP;j>=0;j--)
    50             {
    51                 int nowf=f[pre][j]+BP[i]*j;
    52                 while (head<tail && q[tail-1].f<nowf) tail--;
    53                 q[tail++]=(node){nowf,j};
    54                 while (head<tail && q[head].pos>j+BS[i]) head++;
    55                 f[i][j]=max(f[i][j],q[head].f-BP[i]*j);
    56             }
    57         }
    58     }
    59 }
    60 
    61 void getans()
    62 {
    63     int ans=-INF;
    64     for (int i=0;i<=MaxP;i++) ans=max(ans,f[T][i]);
    65     printf("%d
    ",ans);
    66 }
    67 
    68 int main()
    69 {
    70     init();
    71     dp();
    72     getans();
    73     return 0;
    74 } 
  • 相关阅读:
    jQuery_第一章_JavaScript基础
    呵呵双钻
    MINIDVD
    幸运抽奖
    三章
    复习
    三种循环
    百文买百鸡
    1~100的奇数和
    Python memcache和redis
  • 原文地址:https://www.cnblogs.com/iiyiyi/p/5449579.html
Copyright © 2020-2023  润新知