思路:首先把dp状态方程写出来:设dp[i][j]表示第i天有j个股票的最大值。
那么转移可以有三种情况:在第i+1天什么都不干,dp[i+1][j]=dp[i][j]
在买进一些股票:dp[i+1][j]=max(dp[i+1][j],dp[i+1-w-1][k]-(j-k)*ap
在卖出一些股票:dp[i+1][j]=max(dp[i+1-w-1][k]+(j-k)*bp)
可以发现如果直接写的话,复杂度必然是O(n^3)
如何优化?我们发现每次我们都要枚举k,找出最优的k值来,有没有方法可以让我们直接求出最优的k?
有一点可以确信:dp[i+1][j]>=dp[i][j],因为我不可能在没有改变现有股票的情况下去失去一些利益。换句话说,当j一定时,dp[i][j]是关于i的单调递增函数。
换句话说,dp[i-w][k]完全可以保存下来,当下次需要找dp[i-w]时的最大值时,就可以直接查找。
如何实现? 利用单调队列记录一个单调递减的序列,每次找队首即可。
在具体实现的时候,还要注意有每次买卖的上限。
代码:
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;
const int maxn=2e3+7;
const int mod=1e9+7;
int tim,Mp,w;
struct Point
{
int AP,BP,AS,BS;
}p[maxn];
int dp[maxn][maxn];
deque<int> q;
int cal1(int i,int j)
{
return dp[i-w][j]+p[i].AP*j;
}
int cal2(int i,int j)
{
return dp[i-w][j]+p[i].BP*j;
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("in.txt","r",stdin);
freopen("out.txt","w",stdout);
#endif
int T;
cin>>T;
while(T--)
{
scanf("%d%d%d",&tim,&Mp,&w);
w++;
for(int i=1;i<=tim;i++)
{
scanf("%d%d%d%d",&p[i].AP,&p[i].BP,&p[i].AS,&p[i].BS);
}
for(int i=1;i<=tim;i++) //初始化
{
dp[i][0]=0;
for(int j=1;j<=Mp;j++)
{
dp[i][j]=-inf;
}
}
for(int i=1;i<=w;i++) //预处理第一天的
{
for(int j=1;j<=p[i].AS;j++)
{
dp[i][j]=-j*p[i].AP;
}
}
int i;
for(i=2;i<=w;i++)
{
for(int j=1;j<=Mp;j++)
{
dp[i][j]=max(dp[i][j],dp[i-1][j]);
}
}
int zt=0;
for(;i<=tim;i++)
{
while(q.empty()==0) q.pop_back();//每次都清空队列
for(int j=0;j<=Mp;j++)
{
dp[i][j]=max(dp[i][j],dp[i-1][j]);
zt=dp[i-w][j]+j*p[i].AP;
while(q.empty()==0&&cal1(i,q.back())<zt)
{
q.pop_back();
}
q.push_back(j);
while(q.empty()==0&&j-q.front()>p[i].AS) //维护上限
{
q.pop_front();
}
if(q.empty()==0)
{
dp[i][j]=max(dp[i][j],cal1(i,q.front())-j*p[i].AP);
}
}
while(q.empty()==0) q.pop_back();//减法反着来
for(int j=Mp;j>=0;j--)
{
zt=cal2(i,j);
while(q.empty()==0&&zt>cal2(i,q.back()))
{
q.pop_back();
}
q.push_back(j);
while(q.empty()==0&&q.front()-j>p[i].BS)
{
q.pop_front();
}
if(q.empty()==0)
{
dp[i][j]=max(dp[i][j],cal2(i,q.front())-j*p[i].BP);
}
}
}
int ans=-inf;
for(i=0;i<=Mp;i++)
{
ans=max(dp[tim][i],ans);
}
printf("%d\n",ans);
}
return 0;
}