HDU 3401 Trade
题意:
给定每天的股票买进上限,买进价格,卖出上限,卖出价格,每两次买卖操作中间必须间隔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]
Note:两个过程要分开写 不然WAWAWA
代码:
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
const int N=2010;
const int inf=0x80808080;
typedef pair<int,int> PII;
int T;
int Time,MaxP,W;
int ap[N],bp[N],as[N],bs[N];
int dp[N][N];
PII que[N];
int st,ed;
int main() {
scanf("%d",&T);
while(T--) {
memset(dp[0],inf,sizeof(dp[0]));
dp[0][0]=0;
scanf("%d%d%d",&Time,&MaxP,&W);
for(int i=1;i<=Time;i++) scanf("%d%d%d%d",&ap[i],&bp[i],&as[i],&bs[i]);
int ans=0;
for(int i=1;i<=Time;i++) {
memcpy(dp[i],dp[i-1],sizeof(dp[i]));
if(i<=W+1) {
for(int j=0;j<=as[i];j++) dp[i][j]=max(dp[i-1][j],-ap[i]*j);
continue;
}
st=ed=0;
int pre=i-W-1;
//buy
for(int j=0;j<=MaxP;j++) {
PII elem=PII(dp[pre][j]+j*ap[i],j);
que[ed++]=elem;
while(ed-st>=1 && que[st].second<j-as[i]) st++;
while(ed-st>=2 && que[ed-1].first>=que[ed-2].first) que[ed-2]=que[ed-1],ed--;
dp[i][j]=max(dp[i][j],que[st].first-j*ap[i]);
ans=max(ans,dp[i][j]);
}
st=ed=0;
//sell
for(int j=MaxP;j>=0;j--) {
PII elem=PII(dp[pre][j]+j*bp[i],j);
que[ed++]=elem;
while(ed-st>=1 && que[st].second>j+bs[i]) st++;
while(ed-st>=2 && que[ed-1].first>=que[ed-2].first) que[ed-2]=que[ed-1],ed--;
dp[i][j]=max(dp[i][j],que[st].first-j*bp[i]);
ans=max(ans,dp[i][j]);
}
}
printf("%d\n",ans);
}
return 0;
}