题意:
本金无限,告诉你每天买入卖出的价格和买入卖出的最多总数
让你求n天之后,最多能赚多少
很容易想到DP方程:
dp[i][j]表示第 i 天,有 j 股的最大收益
1.dp[i][j]=max(dp[ i-1 ][ j ],dp[ k ][ t ]-(j-t)*inval[i])
( k<i-w , j-t <= innum[ i ] )
且 dp[i][j]=dp[k][t]+(t-j)*outval[ i ]
(k<i - w, t - j <=outnum[ i ])
然后发现,这是个n^4的(n*p*n*p)
2.其实可以优化成n^3
因为dp[i-1][j]<=dp[i-1][j]
所以,k那一层的枚举可以省略
而改成 i-w-1
3.
最终优化:
对于买入:
dp[i][j]=max(dp[i-w-1][t]-(j-t)*inval[i])
展开括号得到:dp[i][j]=max(dp[i-w-1][t]+t*inval[i])-j*inval[i](因为提出来的式子与t无关)
对于卖出,同理
只是要注意,式子展开后方向是反的(三天三夜)
然后很容易发现,可以用单调队列搞
但是我是不会告诉你单调队列是怎么写的
AC代码如下
#include<bits/stdc++.h>
#define N 2001
using namespace std;
int t,n,p,w;
int innum[N],outnum[N],inval[N],outval[N];
int dp[N][N];
struct data{
int val,id;
};
deque<data>qin,qout;
void insert_out(data x)
{
while(!qout.empty()&&qout.back().val<=x.val)qout.pop_back();
qout.push_back(x);
}
void insert_in(data x)
{
while(!qin.empty()&&qin.back().val<=x.val)qin.pop_back();
qin.push_back(x);
}
void delate_in(int now,int x)
{
while(!qin.empty()&&qin.front().id<x-innum[now])qin.pop_front();
}
void delate_out(int now,int x)
{
while(!qout.empty()&&qout.front().id<x)qout.pop_front();
}
int main()
{
scanf("%d",&t);
while(t--)
{
scanf("%d%d%d",&n,&p,&w);
for(int i=1;i<=n;i++)
scanf("%d%d%d%d",&inval[i],&outval[i],&innum[i],&outnum[i]);
for(int i=0;i<=n;i++)
for(int j=0;j<=p;j++)
dp[i][j]=-1e9;
for(int i=1;i<=w+1;i++)
{
for(int j=0;j<=innum[i];j++)
dp[i][j]=-inval[i]*j;
for(int j=0;j<=p;j++)
dp[i][j]=max(dp[i][j],dp[i-1][j]);
}
data temp;
for(int i=w+2;i<=n;i++)
{
qin.clear();
qout.clear();
int r=i-w-1;
for(int t=0;t<=outnum[i];t++)
{
temp.id=t;
temp.val=dp[r][t]+t*outval[i];
insert_out(temp);
}
for(int j=0;j<=p;j++)
{
dp[i][j]=max(dp[i][j],dp[i-1][j]);
delate_in(i,j);
if(j)dp[i][j]=max(dp[i][j],qin.front().val-j*inval[i]);
delate_out(i,j);
dp[i][j]=max(dp[i][j],qout.front().val-j*outval[i]);
temp.val=dp[r][j]+j*inval[i];
temp.id=j;
insert_in(temp);
if(j+outnum[i]+1<=p)
{
temp.id=j+outnum[i]+1;
temp.val=dp[r][temp.id]+temp.id*outval[i];
insert_out(temp);
}
}
}
int ans=0;
for(int i=0;i<=p;i++)
ans=max(ans,dp[n][i]);
printf("%d\n",ans);
}
}