传送门:bzoj1855
题解
设 f[i][j](1≤i≤n,0≤j≤MaxP) f [ i ] [ j ] ( 1 ≤ i ≤ n , 0 ≤ j ≤ M a x P ) 为第 i i 天结束,手里有股股票的最大利益,对于第 x x 天的情况,分四种情况讨论:
- 净买入股,
f[x][k]=−APx×k
f
[
x
]
[
k
]
=
−
A
P
x
×
k
- 不买不卖, f[x][k]=f[x−1][k](0≤k≤MaxP) f [ x ] [ k ] = f [ x − 1 ] [ k ] ( 0 ≤ k ≤ M a x P )
- 在原来的基础上买入: f[x][k]=maxx−m−1j=1(maxkt=1(f[j][k−t]−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]=maxx−m−1j=1(maxMaxP−kt=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[x][k]=maxkt=1(f[x−m−1][k−t]−t×APx)=maxkt=1(f[x−m−1][k−t]+(k−t)×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 xf[x][k]=maxMaxP−kt=1(f[x−m−1][k+t]+t×BPx)=maxMaxP−kt=1(f[x−m−1][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); }