题目描述
最近 lxhgww 又迷上了投资股票,通过一段时间的观察和学习,他总结出了股票行情的一些规律。
通过一段时间的观察,lxhgww 预测到了未来 T 天内某只股票的走势,第 i 天的股票买入价为每股 AP i
,第 i 天的股票卖出价为每股 BP i (数据保证对于每个 i,都有 AP i ≥BP i ),但是每天不能无限制地交易,于是股票交易所规定第 i 天的一次买入至多只能购买AS i 股,一次卖出至多只能卖出 BS i 股。
另外,股票交易所还制定了两个规定。为了避免大家疯狂交易,股票交易所规定在两次交易(某一天的买入或者卖出均算是一次交易)之间,至少要间隔 W 天,也就是说如果在第 i 天发生了交易,那么从第 i+1 天到第 i+W 天,均不能发生交易。同时,为了避免垄断,股票交易所还规定在任何时间,一个人的手里的股票数不能超过 MaxP。
在第 1 天之前,lxhgww 手里有一大笔钱(可以认为钱的数目无限),但是没有任何股票,当然,T 天以后,lxhgww 想要赚到最多的钱,聪明的程序员们,你们能帮助他吗?
输入格式
输入数据第一行包括 3 个整数,分别是 T,MaxP,W。
接下来 T行,第 i行代表第 i−1 天的股票走势,每行 4 个整数,分别表示 AP i , BP i , AS i , BS i 。
输出格式
输出数据为一行,包括 1 个数字,表示 lxhgww 能赚到的最多的钱数。
输入输出样例
输入 #1
5 2 0
2 1 1 1
2 1 1 1
3 2 1 1
4 3 1 1
5 4 1 1
输出 #1
3
分析:
这道题显然用DP f[i][j]表示i天拥有j张股票赚的钱
共分④种情况:
1 .买空
可直接赋值 即
f[i][j]=-1*ap[i]*j
2 .不买也不卖
直接由上一天转移 并且股票数不变 即
f[i][j]=max(f[i][j],f[i-1][j]);
3 .之前状态下买股票
由于w天内不能交易 所以最近的交易时间为 i - w - 1
x 一定比 j 小 因为最多买AS张 所以底线是 j - as[i]
假设i - w - 1天有x张股票 当前买了 j - x 张 交易额为 ( j - x) * ap[i]
整理一下 得到方程
f[i][j]=max(f[i][j],f[i-w-1][x-(j-x)*ap[i]])
4 .之前状态下卖股票
和情况3差不多 有几点区别
x 一定比 j 大 底线为 j + bs[i]
卖了 j - x 张 交易额为 ( j - x) * bp[i]
与情况3的方程基本一致 把 ap改bp as改bs 就行
符合单调队列的性质 要用单调队列优化
买股票是顺序 卖股票是逆序 其他就没啥了
CODE:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define min(a,b) a<b?a:b
#define max(a,b) a>b?a:b
using namespace std;
int n,maxp,w,as,ap,bs,bp,q[2005],f[2005][2005],ans=0,head,tail;
int main(){
scanf("%d%d%d",&n,&maxp,&w);
memset(f,128,sizeof(f));
for(int i=1;i<=n;i++)
{
scanf("%d%d%d%d",&ap,&bp,&as,&bs);
for(int j=0;j<=as;j++)
f[i][j]=-1*j*ap; //情况1
for(int j=0;j<=maxp;j++)
f[i][j]=max(f[i][j],f[i-1][j]); //情况2
if(i<=w) continue; //如果i<=w会出现负下标
head=1,tail=0; //单调队列
for(int j=0;j<=maxp;j++){
while(head<=tail&&q[head]<j-as) head++;
while(head<=tail&&f[i-w-1][q[tail]]+q[tail]*ap<=f[i-w-1][j]+j*ap) tail--; //单调队列优化
//情况3 顺序
q[++tail]=j; //入队
if(head<=tail)
f[i][j]=max(f[i][j],f[i-w-1][q[head]]+q[head]*ap-j*ap); //DP
}
head=1;tail=0;
for(int j=maxp;j>=0;j--){ //情况4 逆序
while(head<=tail&&q[head]>j+bs) head++;
while(head<=tail&&f[i-w-1][q[tail]]+q[tail]*bp<=f[i-w-1][j]+j*bp) tail--; //单调队列优化
q[++tail]=j; //入队
if(head<=tail)
f[i][j]=max(f[i][j],f[i-w-1][q[head]]+q[head]*bp-j*bp); //DP
}
}
for(int i=0;i<=maxp;i++)
ans=max(ans,f[n][i]); //取最多
printf("%d",ans);
return 0;
}