洛谷P2569 [SCOI2010]股票交易(单调队列)

传送门

惭愧……这种题目都没看出来……

首先,我们用$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 }
原文地址:https://www.cnblogs.com/bztMinamoto/p/9764428.html