题目描述
最近 ext{lxhgww}lxhgww 又迷上了投资股票,通过一段时间的观察和学习,他总结出了股票行情的一些规律。
通过一段时间的观察, ext{lxhgww}lxhgww 预测到了未来 TT 天内某只股票的走势,第 ii 天的股票买入价为每股 AP_iAPi,第 ii 天的股票卖出价为每股 BP_iBPi(数据保证对于每个 ii,都有 AP_i geq BP_iAPi≥BPi),但是每天不能无限制地交易,于是股票交易所规定第 ii 天的一次买入至多只能购买 AS_iASi 股,一次卖出至多只能卖出 BS_iBSi 股。
另外,股票交易所还制定了两个规定。为了避免大家疯狂交易,股票交易所规定在两次交易(某一天的买入或者卖出均算是一次交易)之间,至少要间隔 WW 天,也就是说如果在第 ii 天发生了交易,那么从第 i+1i+1 天到第 i+Wi+W 天,均不能发生交易。同时,为了避免垄断,股票交易所还规定在任何时间,一个人的手里的股票数不能超过 ext{MaxP}MaxP。
在第 11 天之前, ext{lxhgww}lxhgww 手里有一大笔钱(可以认为钱的数目无限),但是没有任何股票,当然,TT 天以后, ext{lxhgww}lxhgww 想要赚到最多的钱,聪明的程序员们,你们能帮助他吗?
输入输出格式
输入格式:
输入数据第一行包括 33 个整数,分别是 TT, ext{MaxP}MaxP,WW。
接下来 TT 行,第 ii 行代表第 i-1i−1 天的股票走势,每行 44 个整数,分别表示 AP_i, BP_i, AS_i, BS_iAPi, BPi, ASi, BSi。
输出格式:
输出数据为一行,包括 11 个数字,表示 ext{lxhgww}lxhgww 能赚到的最多的钱数。
输入输出样例
说明
对于 30\%30% 的数据,0leq W<Tleq 50,1leq ext{MaxP}leq500≤W<T≤50,1≤MaxP≤50
对于 50\%50% 的数据,0leq W<Tleq 2000,1leq ext{MaxP}leq500≤W<T≤2000,1≤MaxP≤50
对于 100\%100% 的数据,0leq W<Tleq 2000,1leq ext{MaxP}leq20000≤W<T≤2000,1≤MaxP≤2000
对于所有的数据,1leq 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的股票能赚的最大金额
- 那么转移其实很显然,有四种情况
- ①凭空买,f[i][j]=-j*ap
- ②不买不卖,f[i][j]=max(f[i][j-1],f[i][j])
- ③在之前的基础上买,f[i][j]=max(f[i][j],f[i-w-1][k]-(j-k)*ap)
- 为什么只有i-w-1呢,因为i-w-2其实在第二种情况时候已经转移到i-w-1了,所以可以只做i-w-1
- ④在之前的基础上卖,f[i][j]=max(f[i][j],f[i-w-1][k]+(k-j)*bp)
- 那么怎么用单调队列优化呢,考虑一下直接dp是三次方的,要做到二次方
- 三四的情况的式子,f[i][j]=max(f[i][j],f[i-w-1][k]-j*ap+k*ap),f[i][j]=max(f[i][j],f[i-w-1][k]-j*ap)+k*ap
- 第四种情况也是类似的,那么这样的话可以发现,其实就是在找一个滑动窗口的最大值
- 显然可以单调队列
代码
1 #include <cstdio> 2 #include <iostream> 3 #include <cstring> 4 using namespace std; 5 int n,m,w,ans,f[2010][2010],Q[2010]; 6 int main() 7 { 8 scanf("%d%d%d",&n,&m,&w); 9 memset(f,128,sizeof(f)); 10 for (int i=1,ap,bp,as,bs;i<=n;i++) 11 { 12 scanf("%d%d%d%d",&ap,&bp,&as,&bs); 13 for (int j=0;j<=as;j++) f[i][j]=-ap*j; 14 for (int j=0;j<=m;j++) f[i][j]=max(f[i][j],f[i-1][j]); 15 if (i<=w) continue; 16 int head=1,tail=0; 17 for (int j=0;j<=m;j++) 18 { 19 while (head<=tail&&Q[head]<j-as) head++; 20 while (head<=tail&&f[i-w-1][Q[tail]]+Q[tail]*ap<=f[i-w-1][j]+j*ap) tail--; 21 Q[++tail]=j; 22 if (head<=tail) f[i][j]=max(f[i][j],f[i-w-1][Q[head]]+Q[head]*ap-j*ap); 23 } 24 head=1; tail=0; 25 for (int j=m;j>=0;j--) 26 { 27 while (head<=tail&&Q[head]>j+bs) head++; 28 while (head<=tail&&f[i-w-1][Q[tail]]+Q[tail]*bp<=f[i-w-1][j]+j*bp) tail--; 29 Q[++tail]=j; 30 if (head<=tail) f[i][j]=max(f[i][j],f[i-w-1][Q[head]]+Q[head]*bp-j*bp); 31 } 32 } 33 for (int i=0;i<=m;i++) ans=max(ans,f[n][i]); 34 printf("%d",ans); 35 }