这道题 我很蒙.....
首先依照搞单调队列优化dp的一般思路 先写出状态转移方程 在想法子去优化
这个题目中说道w就是这一天要是进行操作就是从前w-1天转移而来因为之前的w天
不允许有操作!就是与这些天的状态无关!
那么每一天更新那一天已经定了那么他对后面要转移的地方的影响就是手里的票了
既然这样就加一维表示
f[i][j]表示到第i天手里有j个票的最大收益这样就无后效性了
f[i][j]=Max(f[i][j],f[last][x]-(j-x)*in[i]);
f[i][j]=Max(f[i][j],f[last][x]+(x-j)*out[i]);
f[i][j]=Max(f[i][j],f[i-1][j]);
三种最大即为所求(第三种是不进行任何操作根据状态数组的增性就用前一个状态来修改就行了)
我很蒙......
#include<cstdio> #include<queue> #include<cstring> using namespace std; int f[2005][2005],in[2005],out[2005],inm[2005],outm[2005]; int t,mp,w; deque<int>q; inline int Max(int x,int y) { return x>y?x:y; } inline void push(int i,int j,int x) { while(!q.empty()) { int y=q.back(); if(f[i][j]>=f[i][y]-in[x]*(j-y))q.pop_back(); else{ q.push_back(j);break;} } if(q.empty())q.push_back(j); } inline void pop1(int j) { while(q.front()>j&&!q.empty())q.pop_front(); } inline void push1(int i,int j,int x) { while(!q.empty()) { int y=q.back(); if(f[i][j]>=f[i][y]+out[x]*(y-j))q.pop_back(); else{ q.push_back(j);break;} } if(q.empty())q.push_back(j); } inline void pop(int j) { while(q.front()<j&&!q.empty())q.pop_front(); } int main() { scanf("%d%d%d",&t,&mp,&w); memset(f,0xaf,sizeof(f)); for(int i=1;i<=t;i++)scanf("%d%d%d%d",&in[i],&out[i],&inm[i],&outm[i]); for(int i=1;i<=w+1&&i<=t;i++) { f[i][0]=0; for(int j=1;j<=inm[i];j++) f[i][j]=f[i][j-1]-in[i]; for(int j=0;j<=mp;j++) f[i][j]=Max(f[i][j],f[i-1][j]); } for(int i=w+2,last=1;i<=t;i++,last++) { q.clear(); for(int j=0;j<=mp;j++) { pop(j-inm[i]); push(last,j,i); int x=q.front(); f[i][j]=Max(f[i][j],f[last][x]-(j-x)*in[i]); } q.clear(); for(int j=mp;j>=0;j--) { pop1(j+outm[i]); push1(last,j,i); int x=q.front(); f[i][j]=Max(f[i][j],f[last][x]+(x-j)*out[i]); } for(int j=0;j<=mp;j++) f[i][j]=Max(f[i][j],f[i-1][j]); } int ans=0; for(int i=0;i<=mp;i++)ans=Max(ans,f[t][i]); printf("%d",ans); return 0; }