题意:
一个人有很多钱(无限多),他想搞股票再赚钱,给你接下来d天的股市行情,问他最多能赚多少钱。
首先他每隔w天才能交易,
每天有四个变量,ap,bp,as,bs 分别代表今天股票买入价格,卖出价格,购买最大数量,卖出最大数量。
题解:
应该很容易都想到了dp,推出方程,dp[i][j], 代表前i天身上j支股票的最大盈利值。
1.今天不买也不买,dp[i][j]=max(dp[i][j],dp[i-1][j]);
2.今天买入, dp[i][j]=max(dp[i][j],dp[i-w-1][k]-ap[i]*(j-k));
3.今天卖出, dp[i][j]=max(dp[i][j],dp[i-w-1][k]+bp[i]*(k-j));
O(d*d*maxp*maxp) 这样会超时,
只考虑买入,f(i)= dp[i][k]+k*ap[i];
维护一个单调队列 f(x)=max(f(k)),(j-as[i]<=k<=j);
同理考虑卖出。
令f(x)=max(f(k)), (j<=k<=j+bs[i]);
#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int maxn=2005;
const int inf=1e9;
inline int read(){int x=0,f=1;char c=getchar();for(;!isdigit(c);c=getchar())
if(c=='-')f=-1;for(;isdigit(c);c=getchar())x=x*10+c-'0';return x*f;}
int ap[maxn],bp[maxn],as[maxn],bs[maxn];
int dp[maxn][maxn];
int d,maxp,w,head,tail;
struct node{
int val;
int x;
}que[maxn],t;
int main(){
int ca=read();
while(ca--){
int ans=0;
d=read();maxp=read();w=read();
for(int i=1;i<=d;++i){
ap[i]=read();bp[i]=read();as[i]=read();bs[i]=read();
}
for(int i=0;i<=d;++i)
for(int j=0;j<=maxp;++j)
dp[i][j]=-inf;
for(int i=1;i<=w+1;++i)//可以交易之前都先买入
for(int j=0;j<=min(as[i],maxp);++j)
dp[i][j]=-ap[i]*j;
for(int i=2;i<=d;++i){
for(int j=0;j<=maxp;++j) //不买也不卖
dp[i][j]=max(dp[i][j],dp[i-1][j]);
if(i<=w+1) continue;//初次交易肯定要在w+1天之后。
head=1;tail=0;
for(int j=0;j<=maxp;++j){//买入
t.x=j;
t.val=dp[i-w-1][j]+ap[i]*j;
while(tail>=head&&t.val>que[tail].val) tail--;
que[++tail]=t;
while(tail>=head&&que[head].x<j-as[i]) head++;
if(head<=tail) dp[i][j]=max(dp[i][j],que[head].val-ap[i]*j);
}
head=1;tail=0;
for(int j=maxp;j>=0;--j){//卖出
t.x=j;
t.val=dp[i-w-1][j]+bp[i]*j;
while(tail>=head&&t.val>que[tail].val) tail--;
que[++tail]=t;
while(tail>=head&&que[head].x>j+bs[i]) head++;
if(head<=tail) dp[i][j]=max(dp[i][j],que[head].val-bp[i]*j);
}
}
for(int j=0;j<=maxp;++j)
ans=max(ans,dp[d][j]);
printf("%d\n",ans);
}
return 0;
}