惭愧……这种题目都没看出来……
首先,我们用$dp[i][j]$表示在第$i$天,手上有$j$股时的最大收益
第一,我们可以直接买股票,即$dp[i][j]=-j*AP_i$,这个直接计算即可
第二,我们可以不操作,那么$dp[i][j]=max(dp[i][j],dp[i-1][j])$
第三种,我们买股票,那么$dp[i][j]=max(dp[i][j],dp[i-w-1][k]+k*AP_i-j*AP_i)$
第四种,我们卖股票,那么$dp[i][j]=max(dp[i][j],dp[i-w-1][k]+k*BP_i-j*BP_i)$
然后发现三四两种情况把与$j$有关的提出来之后,里面的可以用单调队列优化
顺便注意情况三要从小到大搞,情况四要从大到小搞
1 //minamoto 2 #include<bits/stdc++.h> 3 using namespace std; 4 #define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++) 5 char buf[1<<21],*p1=buf,*p2=buf; 6 template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;} 7 inline int read(){ 8 #define num ch-'0' 9 char ch;bool flag=0;int res; 10 while(!isdigit(ch=getc())) 11 (ch=='-')&&(flag=true); 12 for(res=num;isdigit(ch=getc());res=res*10+num); 13 (flag)&&(res=-res); 14 #undef num 15 return res; 16 } 17 const int N=2005; 18 int n,m,w,ans,h,t,q[N],dp[N][N]; 19 int main(){ 20 // freopen("testdata.in","r",stdin); 21 n=read(),m=read(),w=read(); 22 memset(dp,0xef,sizeof(dp)); 23 for(int i=1;i<=n;++i){ 24 int ap=read(),bp=read(),as=read(),bs=read(); 25 for(int j=0;j<=as;++j) dp[i][j]=-j*ap; 26 for(int j=0;j<=m;++j) cmax(dp[i][j],dp[i-1][j]); 27 if(i<=w) continue; 28 h=1,t=0; 29 for(int j=0;j<=m;++j){ 30 while(h<=t&&q[h]<j-as) ++h; 31 while(h<=t&&dp[i-w-1][q[t]]+q[t]*ap<=dp[i-w-1][j]+j*ap) --t; 32 q[++t]=j,cmax(dp[i][j],dp[i-w-1][q[h]]+q[h]*ap-j*ap); 33 } 34 h=1,t=0; 35 for(int j=m;j>=0;--j){ 36 while(h<=t&&q[h]>j+bs) ++h; 37 while(h<=t&&dp[i-w-1][q[t]]+q[t]*bp<=dp[i-w-1][j]+j*bp) --t; 38 q[++t]=j,cmax(dp[i][j],dp[i-w-1][q[h]]+q[h]*bp-j*bp); 39 } 40 } 41 for(int i=0;i<=m;++i) cmax(ans,dp[n][i]); 42 printf("%d ",ans); 43 return 0; 44 }