题目描述
最近 lxhgww ext{lxhgww}lxhgww 又迷上了投资股票,通过一段时间的观察和学习,他总结出了股票行情的一些规律。
通过一段时间的观察,lxhgww ext{lxhgww}lxhgww 预测到了未来 TTT 天内某只股票的走势,第 iii 天的股票买入价为每股 APiAP_iAPi,第 iii 天的股票卖出价为每股 BPiBP_iBPi(数据保证对于每个 iii,都有 APi≥BPiAP_i geq BP_iAPi≥BPi),但是每天不能无限制地交易,于是股票交易所规定第 iii 天的一次买入至多只能购买 ASiAS_iASi 股,一次卖出至多只能卖出 BSiBS_iBSi 股。
另外,股票交易所还制定了两个规定。为了避免大家疯狂交易,股票交易所规定在两次交易(某一天的买入或者卖出均算是一次交易)之间,至少要间隔 WWW 天,也就是说如果在第 iii 天发生了交易,那么从第 i+1i+1i+1 天到第 i+Wi+Wi+W 天,均不能发生交易。同时,为了避免垄断,股票交易所还规定在任何时间,一个人的手里的股票数不能超过 MaxP ext{MaxP}MaxP。
在第 111 天之前,lxhgww ext{lxhgww}lxhgww 手里有一大笔钱(可以认为钱的数目无限),但是没有任何股票,当然,TTT 天以后,lxhgww ext{lxhgww}lxhgww 想要赚到最多的钱,聪明的程序员们,你们能帮助他吗?
输入输出格式
输入格式:输入数据第一行包括 333 个整数,分别是 TTT,MaxP ext{MaxP}MaxP,WWW。
接下来 TTT 行,第 iii 行代表第 i−1i-1i−1 天的股票走势,每行 444 个整数,分别表示 APi, BPi, ASi, BSiAP_i, BP_i, AS_i, BS_iAPi, BPi, ASi, BSi。
输出格式:输出数据为一行,包括 111 个数字,表示 lxhgww ext{lxhgww}lxhgww 能赚到的最多的钱数。
输入输出样例
说明
对于 30%30\%30% 的数据,0≤W<T≤50,1≤MaxP≤500leq W<Tleq 50,1leq ext{MaxP}leq500≤W<T≤50,1≤MaxP≤50
对于 50%50\%50% 的数据,0≤W<T≤2000,1≤MaxP≤500leq W<Tleq 2000,1leq ext{MaxP}leq500≤W<T≤2000,1≤MaxP≤50
对于 100%100\%100% 的数据,0≤W<T≤2000,1≤MaxP≤20000leq W<Tleq 2000,1leq ext{MaxP}leq20000≤W<T≤2000,1≤MaxP≤2000
对于所有的数据,1≤BPi≤APi≤1000,1≤ASi,BSi≤MaxP1leq BP_ileq AP_ileq 1000,1leq AS_i,BS_ileq ext{MaxP}1≤BPi≤APi≤1000,1≤ASi,BSi≤MaxP
首先dp很好想,f[i][j] 代表前i天,有j个股票的可以赚到的最多的钱
一、第i天不买股票也不买
那就是从前一天相同的股票值更新过来
f[i][j]=max(f[i][j],f[i-1][j]);
那为什么是前一天而不是前几天呢?因为前几天的最优值都已经更新到前一天了呀。
二、第i天凭空买股票(相当于从之前手持0股票的情况更新来)
其实就是第i天的DP数组的初始化
For(j,0,As[i]) f[i] [j]=-j * Ap[i];
三、第i天在第 i-w-1 天的基础上买股票
那我们设第i-w-1天的股票数为k,最直接的更新就是下面这样
f[i][j]=max(f[i][j], f[i-w-1][k]-(j-k)* Ap[i]);
但我们此时要更新的是j,所以可以稍稍转化一下:
f[i][j]=max{ f[i-w-1][k]+ k Ap[i] } - j* Ap[i]
所以在k的取值范围上,
有经验的OIer们应该都能想到单调队列了吧(!)
式子中有取max值,还有取值范围的经常都是用单调队列来优化(不知道具体如何操作的可以看代码
四、第i天在第i-w-1天的基础上卖出股票
和上一种情况其实是一样的(式子的推导请参照上式自己操作)
f[i][j]=max{f[i-w-1][k]+kBp[i]}- j Ap[i]
只是k的取值范围不一样了,变成了(j, j+Bs[i] ]
同样可以用单调队列来优化。
代码~
1 #include<iostream>
2 #include<cstdio>
3 #include<cstdlib>
4 #include<cstring>
5 #include<algorithm>
6
7 #define For(i,a,b) for(register int i=a;i<=b;++i)
8 #define Dwn(i,a,b) for(register int i=a;i>=b;--i)
9 #define Re register
10
11 using namespace std;
12
13 const int N=2e3+10;
14 int f[N][N],q[N*2],qf,qr;
15 int n,m,As[N],Ap[N],Bs[N],Bp[N],W,T,MaxP;
16 inline void read(int &v){
17 v=0;
18 char c=getchar();
19 while(c<'0'||c>'9')c=getchar();
20 while(c>='0'&&c<='9')v=v*10+c-'0',c=getchar();
21 }
22 int main(){
23 read(T); read(MaxP); read(W);
24 For(i,1,T){
25 read(Ap[i]); read(Bp[i]);
26 read(As[i]); read(Bs[i]);
27 }
28 memset(f,128,sizeof(f));
29 For(i,1,T){
30 // I bought some stocks from nowhere
31 For(j,0,As[i]){
32 f[i][j]=-1*j*Ap[i];
33 }
34 // I didn't buy anything
35 For(j,0,MaxP){
36 f[i][j]=max(f[i][j],f[i-1][j]);
37 }
38
39 if(i-W-1<=0)continue;
40
41 // I bought some stock today after W days
42 qf=1; qr=0;
43 For(j,0,MaxP){
44 while(qf<=qr&&q[qf]<j-As[i])qf++;
45 if(qf<=qr){
46 int k=q[qf];
47 f[i][j]=max(f[i][j],f[i-W-1][k]+k*Ap[i]-j*Ap[i]);
48 }
49 while(qf<=qr&&f[i-W-1][q[qr]]+q[qr]*Ap[i]<=f[i-W-1][j]+j*Ap[i])qr--;
50 q[++qr]=j;
51 }
52
53 // I sold some stock today after W days
54 qf=1; qr=0;
55 Dwn(j,MaxP,0){
56 while(qf<=qr&&q[qf]>j+Bs[i])qf++;
57 if(qf<=qr){
58 int k=q[qf];
59 f[i][j]=max(f[i][j],f[i-W-1][k]+k*Bp[i]-j*Bp[i]);
60 }
61 while(qf<=qr&&f[i-W-1][q[qr]]+q[qr]*Bp[i]<=f[i-W-1][j]+j*Bp[i])qr--;
62 q[++qr]=j;
63 }
64 }
65 int fn=-2147483600;
66 For(i,0,MaxP)fn=max(fn,f[T][i]);
67 cout<<fn<<endl;
68 return 0;
69 }