【BZOJ】1855: [Scoi2010]股票交易-队列优化DP

传送门:bzoj1855


题解

f[i][j](1in,0jMaxP) f [ i ] [ j ] ( 1 ≤ i ≤ n , 0 ≤ j ≤ M a x P ) 为第 i i 天结束,手里有j股股票的最大利益,对于第 x x 天的情况,分四种情况讨论:

  • 净买入k(0kASx)股, f[x][k]=APx×k f [ x ] [ k ] = − A P x × k

    • 不买不卖, f[x][k]=f[x1][k](0kMaxP) f [ x ] [ k ] = f [ x − 1 ] [ k ] ( 0 ≤ k ≤ M a x P )
    • 在原来的基础上买入: f[x][k]=maxxm1j=1(maxkt=1(f[j][kt]t×APx)) f [ x ] [ k ] = m a x j = 1 x − m − 1 ( m a x t = 1 k ( f [ j ] [ k − t ] − t × A P x ) ) ,
    • 在原来的基础上卖出: f[x][k]=maxxm1j=1(maxMaxPkt=1(f[j][k+t]+t×BPx)) f [ x ] [ k ] = m a x j = 1 x − m − 1 ( m a x t = 1 M a x P − k ( f [ j ] [ k + t ] + t × B P x ) )
    • 四种情况取 max m a x 转移即可。

      由于对于特定的 j j f[i][j](1in)是单调不下降的,所以简化后两个转移式为:
      f[x][k]=maxkt=1(f[xm1][kt]t×APx)=maxkt=1(f[xm1][kt]+(kt)×APx)k×APx f [ x ] [ k ] = m a x t = 1 k ( f [ x − m − 1 ] [ k − t ] − t × A P x ) = m a x t = 1 k ( f [ x − m − 1 ] [ k − t ] + ( k − t ) × A P x ) − k × A P x

      f[x][k]=maxMaxPkt=1(f[xm1][k+t]+t×BPx)=maxMaxPkt=1(f[xm1][k+t]+(k+t)×BPx)k×BPx f [ x ] [ k ] = m a x t = 1 M a x P − k ( f [ x − m − 1 ] [ k + t ] + t × B P x ) = m a x t = 1 M a x P − k ( f [ x − m − 1 ] [ k + t ] + ( k + t ) × B P x ) − k × B P x

      单调队列优化即可。


      代码

      #include<bits/stdc++.h>
      #define gc getchar()
      #define si isdigit(c)
      #define RI register
      using namespace std;
      const int N=2020;
      int n,m,w,ap,bp,as,bs;
      int q[N],l,r,f[N][N],ans;
      
      char c;
      inline void rd(int &x)
      {
          c=gc;x=0;int f=0;
          for(;!si;c=gc) if(c=='-') f=1;
          for(;si;c=gc) x=x*10+(c^48);
          if(f) x=-x;
      }
      
      int main(){
          RI int i,j;
          memset(f,128,sizeof(f));
          rd(n);rd(m);rd(w);
          for(i=1;i<=n;++i){
             rd(ap);rd(bp);rd(as);rd(bs);
             for(j=0;j<=as;++j) f[i][j]=-j*ap;
             for(j=0;j<=m;++j) f[i][j]=max(f[i][j],f[i-1][j]);
             if(i<=w) continue;
             l=1,r=0;
             for(j=0;j<=m;++j){
                 for(;l<=r && q[l]<j-as;++l);
                 for(;l<=r && f[i-w-1][q[r]]+q[r]*ap<=f[i-w-1][j]+j*ap;--r);
                 q[++r]=j;
                 if(l<=r) f[i][j]=max(f[i][j],f[i-w-1][q[l]]+(q[l]-j)*ap);
             }
             l=1,r=0;
             for(j=m;j>=0;--j){
                 for(;l<=r && q[l]>j+bs;++l);
                 for(;l<=r && f[i-w-1][q[r]]+q[r]*bp<=f[i-w-1][j]+j*bp;--r);
                 q[++r]=j;
                 if(l<=r) f[i][j]=max(f[i][j],f[i-w-1][q[l]]+(q[l]-j)*bp);
             }
          } 
          ans=-2e9;
          for(i=0;i<=m;++i) ans=max(ans,f[n][i]);
          printf("%d\n",ans);
      }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值