题意:
给定每天的股票买进上限,买进价格,卖出上限,卖出价格,每两次买卖操作中间必须间隔w天,每天最多持有maxp个股票,问n天后最大收益是多少
题解:
DP方程显然:
dp[i][j]=max(不买不卖,买入操作,卖出操作)
不买不卖
dp[i][j]=max(dp[i][j],dp[i-1][j])
买
dp[i][j]=max(dp[pre][k]-(j-k)*AP[i])
dp[i][j]+j*AP[i]=max(dp[pre][k]+k*AP[i])
令f(k)=dp[i][k]+k*AP[i]
f(j)=max(f(k)) (j-AS[i]<=k<=j)//经典单调队列
所以dp[i][j]=f(j)-j*AP[i]
卖
dp[i][j]=max(dp[pre][k]+(k-j)*BP[[i])
dp[i][j]+j*BP[i]=max(dp[pre][k]+k*BP[i])
令ff(k)=dp[i][k]+k*AP[i]
ff(j)=max(ff(k)) (j<=k<=j+BS[i])
所以dp[i][j]=ff(j)-j*BP[i]
/*
* File: main.cpp
* Author: swordholy
*
* Created on 2011年3月16日, 下午1:11
*/
#include<iostream>
#include<algorithm>
#include <stdio.h>
using namespace std;
#define MAXN 2010
#define INF 200000000
int max(int x,int y)
{
if (x>y) return x;
else return y;
}
int min(int x,int y)
{
if (x<y) return x;
else return y;
}
struct ST
{
int k;
int f;
};
ST q[MAXN];
int qh,qt;//Qhead,Qtail
int AP[MAXN],BP[MAXN],AS[MAXN],BS[MAXN];
int dp[MAXN][MAXN];
/*
不买不卖
dp[i][j]=max(dp[i][j],dp[i-1][j])
买
dp[i][j]=max(dp[pre][k]-(j-k)*AP[i])
dp[i][j]+j*AP[i]=max(dp[pre][k]+k*AP[i])
令f(k)=dp[i][k]+k*AP[i]
f(j)=max(f(k)) (j-AS[i]<=k<=j)//经典单调队列
所以dp[i][j]=f(j)-j*AP[i]
卖
dp[i][j]=max(dp[pre][k]+(k-j)*BP[[i])
dp[i][j]+j*BP[i]=max(dp[pre][k]+k*BP[i])
令ff(k)=dp[i][k]+k*AP[i]
ff(j)=max(ff(k)) (j<=k<=j+BS[i])
所以dp[i][j]=ff(j)-j*BP[i]
*/
int main()
{
int tcase,n,maxp,w,pre,j,l,ans,i,head,tail,nowf,nowk;
ST temp,next,now;
scanf("%d",&tcase);
while(tcase--)
{
scanf("%d%d%d",&n,&maxp,&w);
for(i=1;i<=n;i++)
scanf("%d%d%d%d",&AP[i],&BP[i],&AS[i],&BS[i]);
for(i=0;i<=n;i++)
for(j=0;j<=maxp;j++)
dp[i][j]=-INF;
for (i=1;i<=w+1;i++)
{
for (j=0;j<=min(AS[i],maxp);j++) dp[i][j]=-AP[i]*j;
}
dp[0][0]=0;
for(i=1;i<=n;i++)
{
//不买不卖
for(j=0;j<=maxp;j++)
dp[i][j]=max(dp[i-1][j],dp[i][j]);
if (i<=w+1)//第1天有交易也要第w+2后才能再次交易
continue;
pre=i-w-1;
//买
head=1;tail=0;
for(j=0;j<=maxp;j++)
{
nowf=dp[pre][j]+AP[i]*j;
nowk=j;
while(head<=tail&&q[tail].f<nowf) tail--;
++tail;q[tail].f=nowf;q[tail].k=nowk;
while(head<=tail&&q[head].k+AS[i]<j) head++;
dp[i][j]=max(dp[i][j],q[head].f-j*AP[i]);
}
//卖
head=1;tail=0;
for(j=maxp;j>=0;j--)
{
nowf=dp[pre][j]+BP[i]*j;
nowk=j;
while(head<=tail&&q[tail].f<nowf) tail--;
++tail;q[tail].f=nowf;q[tail].k=nowk;
while(head<=tail&&j+BS[i]<q[head].k) head++;
dp[i][j]=max(dp[i][j],q[head].f-j*BP[i]);
}
}
int ans=0;
for(int i=0;i<=maxp;++i)ans=max(ans,dp[n][i]);
printf("%d/n",ans);
}
}