标签:接下来 pre 整数 led tchar ons rip esc 表达
对于30%的数据,0 < =W 对于50%的数据,0 < =W 对于100%的数据,0 < =W
对于所有的数据,1 < =BPi < =APi < =1000,1 < =ASi,BSi < =MaxP
/* 方法:单调队列优化DP 设f[i][j]代表前i天有j份股票时的最大利润。 三种更新: 1.不交易:f[i][j]=max(f[i][j],f[i-1][j]); 2.买入:f[i][j]=max(f[i][j],f[i-w-1][k]-(j-k)*AP[i])(k>=j-AS[i]); 3.卖出:f[i][j]=max(f[i][j],f[i-w-1][k]+(k-j)*BP[i])(k<=max(maxp,j+BS[i])) 然后我们观察式子,第一种更新O(1)完成, 第二和第三的时候如果枚举k的话复杂度承受不了,所以考虑怎么优化, 显而易见第二三种是线性的,所以考虑到队列可不可行? 于是整理表达式,发现可行,则按照f[i-w-1][k]+k*AP[i]以及f[i-w-1][k]+k*BP[i]维护递减即可。 */ #include<cstdio> #include<cstring> #include<iostream> #define set(x) freopen(#x".in","r",stdin);freopen(#x".out","w",stdout); using namespace std; inline int read(){ int x=0,f=1;char ch=getchar(); while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();} while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();} return x*f; } const int N=2001; int n,maxp,w,ans,AP[N],BP[N],AS[N],BS[N]; int f[N][N],q[N]; int main(){ set(trade) n=read();maxp=read();w=read(); for(int i=1;i<=n;i++) AP[i]=read(),BP[i]=read(),AS[i]=read(),BS[i]=read(); memset(f,-0x3f,sizeof f); for(int i=1;i<=n;i++){ for(int j=0;j<=AS[i];j++) f[i][j]=-AP[i]*j; for(int j=0;j<=maxp;j++) f[i][j]=max(f[i][j],f[i-1][j]); int d=i-w-1; if(d>=0){ int h=0,t=0; for(int j=0;j<=maxp;j++){ while(h<t&&q[h]<j-AS[i]) h++; while(h<t&&f[d][j]+j*AP[i]>=f[d][q[t-1]]+q[t-1]*AP[i]) t--; q[t++]=j; if(h<t) f[i][j]=max(f[i][j],f[d][q[h]]-(j-q[h])*AP[i]); } h=0,t=0; for(int j=maxp;j>=0;j--){ while(h<t&&q[h]>j+BS[i]) h++; while(h<t&&f[d][j]+j*BP[i]>=f[d][q[t-1]]+q[t-1]*BP[i]) t--; q[t++]=j; if(h<t) f[i][j]=max(f[i][j],f[d][q[h]]+(q[h]-j)*BP[i]); } } } for(int i=0;i<=maxp;i++) ans=max(ans,f[n][i]); printf("%d\n",ans); return 0; } /*zjk‘s 60分 #include<cstdio> #include<iostream> #include<cstring> #define N 2010 using namespace std; int ap[N],bp[N],as[N],bs[N],f[N][N],n,m,w; int main(){ freopen("trade.in","r",stdin); freopen("trade.out","w",stdout); scanf("%d%d%d",&n,&m,&w); for(int i=1;i<=n;i++) scanf("%d%d%d%d",&ap[i],&bp[i],&as[i],&bs[i]); memset(f,-127/3,sizeof(f)); for(int i=1;i<=n;i++) for(int j=0;j<=as[i];j++) f[i][j]=-j*ap[i]; for(int i=1;i<=n;i++){ for(int j=0;j<=m;j++){ f[i][j]=max(f[i][j],f[i-1][j]); for(int k=1;k<=i-w-1;k++){ //买入 for(int l=max(j-as[i],0);l<=j-1;l++) f[i][j]=max(f[i][j],f[k][l]-(j-l)*ap[i]); //卖出 for(int l=j+1;l<=min(j+bs[i],m);l++) f[i][j]=max(f[i][j],f[k][l]+(l-j)*bp[i]); } } } printf("%d",max(f[n][0],0)); return 0; } */ /*30+10暴力dp #include<cstdio> #include<cstring> #include<iostream> #define set(x) freopen(#x".in","r",stdin);freopen(#x".out","w",stdout); using namespace std; inline int read(){ int x=0,f=1;char ch=getchar(); while(ch<‘0‘||ch>‘9‘){if(ch==‘-‘)f=-1;ch=getchar();} while(ch>=‘0‘&&ch<=‘9‘){x=x*10+ch-‘0‘;ch=getchar();} return x*f; } const int N=2001; int n,maxp,w,ans,AP[N],BP[N],AS[N],BS[N]; int f[N][N][2]; //1/0 have traded or not int dfs(int cur,int num,bool d){ int &res=f[cur][num][d]; if(~res) return res; res=0; if(cur>=n) return res; for(int i=(d?cur+w+1:cur+1);i<=n;i++){ res=max(res,dfs(i,num,0)); for(int j=1;j<=(maxp-num,AS[i]);j++){ res=max(res,dfs(i,num+j,1)-j*AP[i]); } for(int j=1;j<=min(num,BS[i]);j++){ res=max(res,dfs(i,num-j,1)+j*BP[i]); } } return res; } void dp(){ for(int i=n-1,t;~i;i--){ for(int j=0;j<=maxp;j++){ for(int d=0;d<2;d++){ for(int k=(d?i+w+1:i+1);k<=n;k++){ int &res=f[i][j][d]; res=max(res,f[k][j][0]); for(int h=1;h<=min(maxp-j,AS[k]);h++){ res=max(res,f[k][j+h][1]-h*AP[k]); } for(int h=1;h<=min(j,BS[k]);h++){ res=max(res,f[k][j-h][1]+h*BP[k]); } } } } } } int main(){ set(trade); n=read();maxp=read();w=read(); for(int i=1;i<=n;i++) AP[i]=read(),BP[i]=read(),AS[i]=read(),BS[i]=read(); if(n<=50&&maxp<=50) dp(); else{ memset(f,-1,sizeof f); dfs(0,0,0); } printf("%d\n",f[0][0][0]); return 0; }*/
1855: [Scoi2010]股票交易[单调队列优化DP]
标签:接下来 pre 整数 led tchar ons rip esc 表达
原文地址:http://www.cnblogs.com/shenben/p/6623651.html