题解:
单调队列优化DP
用f[i][j]表示第 i 天持有 j 股股票的最大收益
首先发现状态转移时 i 是不需要枚举的,一定从 i-w-1 天转移而来
然后对于买入和卖出分别建一个单调队列即可
//by sdfzchy
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long LL;
const int inf=(1<<30),N=2010;
int n,m;
inline int in()
{
char ch=getchar();
int f=1,tmp=0;
while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=getchar();}
while(ch>='0'&&ch<='9') {tmp=(tmp<<1)+(tmp<<3)+(ch-'0');ch=getchar();}
return tmp*f;
}
int p,w;
int a[N],b[N],c[N],d[N];
int f[N][N];
struct Q
{
int pos,val;
}q[N];
int main()
{
int T=in();
while(T--)
{
memset(f,0xaf,sizeof(f)); f[0][0]=0;
n=in(),p=in(),w=in();
for(int i=1;i<=n;i++) a[i]=in(),b[i]=in(),c[i]=in(),d[i]=in();
for(int i=1;i<=w+1;i++)
for(int j=0;j<=c[i];j++)
f[i][j]=-j*a[i];
for(int i=1;i<=n;i++)
{
if(i<=w+1)
{
for(int j=0;j<=p;j++)
f[i][j]=max(f[i][j],f[i-1][j]);
continue;
}
int l=1,r=0;
for(int j=0;j<=p;j++)
{
f[i][j]=max(f[i-1][j],f[i][j]);
int cur=f[i-w-1][j]+j*a[i];
while(l<=r&&q[r].val<=cur) r--;
q[++r]=(Q){j,cur};
while(l<=r&&j-q[l].pos>c[i]) l++;
f[i][j]=max(f[i][j],q[l].val-j*a[i]);
}
l=1,r=0;
for(int j=p;j>=0;j--)
{
int cur=f[i-w-1][j]+j*b[i];
while(l<=r&&q[r].val<=cur) r--;
q[++r]=(Q){j,cur};
while(l<=r&&q[l].pos-j>d[i]) l++;
f[i][j]=max(f[i][j],q[l].val-j*b[i]);
}
}
printf("%d\n",f[n][0]);
}
return 0;
}