题目
第iii天的股票买入价为每股APiAPiAPi,第i天的股票卖出价为每股BPiBPiBPi(数据保证对于每个iii,都有APi≥BPiAPi\geq BPiAPi≥BPi),规定第iii天的一次买入至多只能购买ASiASiASi股,一次卖出至多只能卖出BSiBSiBSi股。两次交易(某一天的买入或者卖出均算是一次交易)之间,至少要间隔WWW天,也就是说如果在第iii天发生了交易,那么从第i+1i+1i+1天到第i+Wi+Wi+W天,均不能发生交易。一个人的手里的股票数不能超过MaxPMaxPMaxP。TTT天以后,问最多获利多少钱
分析
f[i][j]f[i][j]f[i][j]表示第iii天结束后,手里剩下jjj股的最大利润
- 不买不卖:f[i][j]=f[i−1][j]f[i][j]=f[i-1][j]f[i][j]=f[i−1][j]
- 买入:
f[i][j]=max(f[i−w−1][k]−ap[i]∗(j−k))f[i][j]=\max(f[i-w-1][k]-ap[i]*(j-k))f[i][j]=max(f[i−w−1][k]−ap[i]∗(j−k))
(j−as[i]≤k<j)(j-as[i]\leq k<j)(j−as[i]≤k<j) - 卖出:
f[i][j]=max(f[i−w−1][k]+bp[i]∗(k−j))f[i][j]=\max(f[i-w-1][k]+bp[i]*(k-j))f[i][j]=max(f[i−w−1][k]+bp[i]∗(k−j))
(j<k≤j+bs[i])(j<k\leq j+bs[i])(j<k≤j+bs[i])
但是问题是O(TW2)O(TW^2)O(TW2)会超时,那么改一改
- 买入:
f[i][j]=max(f[i−w−1][k]+ap[i]∗k)−ap[i]∗jf[i][j]=\max(f[i-w-1][k]+ap[i]*k)-ap[i]*jf[i][j]=max(f[i−w−1][k]+ap[i]∗k)−ap[i]∗j - 卖出:
f[i][j]=max(f[i−w−1][k]+bp[i]∗k)−bp[i]∗jf[i][j]=\max(f[i-w-1][k]+bp[i]*k)-bp[i]*jf[i][j]=max(f[i−w−1][k]+bp[i]∗k)−bp[i]∗j
那么就可以用单调队列来解决,求出最优的k
代码
#include <cstdio>
#include <cstring>
using namespace std;
int n,maxp,w,ap[2001],bp[2001],as[2001],bs[2001],f[2001][2001],q[2001];
int in(){
int ans=0; char c=getchar();
while (c<48||c>57) c=getchar();
while (c>47&&c<58) ans=ans*10+c-48,c=getchar();
return ans;
}
int max(int a,int b){return (a<b)?b:a;}
int main(){
n=in(); maxp=in(); w=in(); memset(f,-0x7f,sizeof(f));
for (int i=1;i<=n;i++) ap[i]=in(),bp[i]=in(),as[i]=in(),bs[i]=in();
for (int i=0;i<=n;i++) f[i][0]=0;//没有股票为0
for (int i=1;i<=n;i++){
for (int j=0;j<=as[i];j++) f[i][j]=-ap[i]*j;//买了该股票花钱
for (int j=maxp;j>=0;j--) f[i][j]=max(f[i][j],f[i-1][j]);//不买股票
if (i>w){//可以交易
int head=1,tail=0;
for (int j=0;j<=maxp;j++){
while (head<=tail&&q[head]<j-as[i]) head++;//股票数量不够
while (head<=tail&&f[i-w-1][j]+ap[i]*j>=f[i-w-1][q[tail]]+ap[i]*q[tail]) tail--;//更优的答案
q[++tail]=j;
if (head<=tail) f[i][j]=max(f[i][j],f[i-w-1][q[head]]-ap[i]*(j-q[head]));//dp
}
head=1; tail=0;
for (int j=maxp;j>=0;j--){
while (head<=tail&&q[head]>j+bs[i]) head++;//股票不够
while (head<=tail&&f[i-w-1][j]+bp[i]*j>=f[i-w-1][q[tail]]+bp[i]*q[tail]) tail--;//更优的答案
q[++tail]=j;
if (head<=tail) f[i][j]=max(f[i][j],f[i-w-1][q[head]]+bp[i]*(q[head]-j));//dp
}
}
}
int ans=0;
for (int i=0;i<=maxp;i++) ans=max(ans,f[n][i]);//找到最好的答案
return !printf("%d",ans);
}
PS:SSL 1943 vijos new_bzoj