题目链接:https://loj.ac/problem/10183
解题思路
dp[i][j]表示到第i天有j股股票的最大值,在第i天可以啥都不干,dp[i][j]=max(dp[i][j],dp[i-1][j]),也可以购买或者出售股票,前提前W天未操作股票,dp[i][j]=max(dp[i-W-1][j-k1]-k1*ap[i],dp[i-W-1][j+k2]+k2*bp[i])1<=k1<=as[i],1<=k2<=bs[i]。以t=i-W-1,x=j-k1,y=j+k2。
原式可替换如下,dp[i][j]=max(dp[t][x]+x*ap[i]-j*ap[i],dp[t][y]+y*bp[i]-j*bp[i])。这就可以用单调队列去优化。
AC代码
#include <iostream>
#include <stdio.h>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int N=2e3+5;
const ll inf=1ll<<62;
ll dp[N][N];
int T,maxP,W;
int ap[N],bp[N],as[N],bs[N];
struct node
{
ll val;
int pos;
}q[N];
int l,r;
int main()
{
scanf("%d%d%d",&T,&maxP,&W);
for(int i=1;i<=T;++i)
scanf("%d%d%d%d",&ap[i],&bp[i],&as[i],&bs[i]);
for(int i=0;i<=T;++i)
for(int j=0;j<=maxP;++j)
dp[i][j]=-inf;
//dp[0][0]=0;
ll ans=-inf;
for(int i=1;i<=T;++i)
{
for(int j=0;j<=as[i];++j)
dp[i][j]=-ap[i]*j;
for(int j=0;j<=maxP;++j)
dp[i][j]=max(dp[i-1][j],dp[i][j]);
int t=i-W-1;
if(t>0)
{
l=r=0;
for(int j=0;j<=maxP;++j)
{
while(l<r&&(j-q[l].pos)>as[i])
l++;
while(l<r&&q[r-1].val<=dp[t][j]+1ll*j*ap[i])
r--;
q[r].pos=j;
q[r++].val=dp[t][j]+1ll*j*ap[i];
if(l<r)
dp[i][j]=max(dp[i][j],q[l].val-1ll*j*ap[i]);
}
l=r=0;
for(int j=maxP;j>=0;j--)
{
while(l<r&&(q[l].pos-j)>bs[i])
l++;
while(l<r&&q[r-1].val<=dp[t][j]+1ll*j*bp[i])
r--;
q[r].pos=j;
q[r++].val=dp[t][j]+1ll*j*bp[i];
if(l<r)
dp[i][j]=max(dp[i][j],q[l].val-1ll*j*bp[i]);
}
}
}
for(int i=0;i<=maxP;++i)
ans=max(ans,dp[T][i]);
printf("%lld\n",ans);
return 0;
}