[SCOI2010] 股票交易
题目描述
最近 lxhgwwlxhgww 又迷上了投资股票,通过一段时间的观察和学习,他总结出了股票行情的一些规律。
通过一段时间的观察,lxhgwwlxhgww 预测到了未来 TT 天内某只股票的走势,第 ii 天的股票买入价为每股 APiAPi,第 ii 天的股票卖出价为每股 BPiBPi(数据保证对于每个 ii,都有 APi≥BPiAPi≥BPi),但是每天不能无限制地交易,于是股票交易所规定第 ii 天的一次买入至多只能购买 ASiASi 股,一次卖出至多只能卖出 BSiBSi 股。
另外,股票交易所还制定了两个规定。为了避免大家疯狂交易,股票交易所规定在两次交易(某一天的买入或者卖出均算是一次交易)之间,至少要间隔 WW 天,也就是说如果在第 ii 天发生了交易,那么从第 i+1i+1 天到第 i+Wi+W 天,均不能发生交易。同时,为了避免垄断,股票交易所还规定在任何时间,一个人的手里的股票数不能超过 MaxPMaxP。
在第 11 天之前,lxhgwwlxhgww 手里有一大笔钱(可以认为钱的数目无限),但是没有任何股票,当然,TT 天以后,lxhgwwlxhgww 想要赚到最多的钱,聪明的程序员们,你们能帮助他吗?
输入格式
输入数据第一行包括 33 个整数,分别是 TT,MaxPMaxP,WW。
接下来 TT 行,第 ii 行代表第 i−1i−1 天的股票走势,每行 44 个整数,分别表示 APi, BPi, ASi, BSiAPi, BPi, ASi, BSi。
输出格式
输出数据为一行,包括 11 个数字,表示 lxhgwwlxhgww 能赚到的最多的钱数。
输入输出样例
5 2 0 2 1 1 1 2 1 1 1 3 2 1 1 4 3 1 1 5 4 1 1
3
说明/提示
- 对于 30%30% 的数据,0≤W<T≤50,1≤MaxP≤500≤W<T≤50,1≤MaxP≤50;
- 对于 50%50% 的数据,0≤W<T≤2000,1≤MaxP≤500≤W<T≤2000,1≤MaxP≤50;
- 对于 100%100% 的数据,0≤W<T≤2000,1≤MaxP≤20000≤W<T≤2000,1≤MaxP≤2000;
- 对于所有的数据,1≤BPi≤APi≤1000,1≤ASi,BSi≤MaxP1≤BPi≤APi≤1000,1≤ASi,BSi≤MaxP。
额,化完的式子长这样,然后就直接单调队列优化就好了
#include<bits/stdc++.h> #define ll long long using namespace std; inline int read() { char c=getchar();int a=0,b=1; for(;c<'0'||c>'9';c=getchar())if(c=='-')b=-1; for(;c>='0'&&c<='9';c=getchar())a=a*10+c-48;return a*b; } int n,w,f[2001][2001],Maxp; struct rec { int ap,bp,as,bs; }a[2001]; int que[2001],head,tail; int main() { // freopen(".in","r",stdin); // freopen(".out","w",stdout); n=read();Maxp=read(),w=read(); for(int i=1;i<=n;i++) { a[i].ap=read(); a[i].bp=read(); a[i].as=read(); a[i].bs=read(); } memset(f,128,sizeof(f)); for(int i=1;i<=n;i++) { head=1;tail=0; for(int j=0;j<=a[i].as;j++) { f[i][j]=-1*a[i].ap*j; } for(int j=0;j<=Maxp;j++) { f[i][j]=max(f[i][j],f[i-1][j]); } if(i<=w)continue; for(int j=0;j<=Maxp;j++) { while(head<=tail&&que[head]<j-a[i].as)head++; while(head<=tail&&f[i-w-1][j]+j*a[i].ap>=f[i-w-1][que[tail]]+que[tail]*a[i].ap)tail--; que[++tail]=j; if(head<=tail) f[i][j]=max(f[i][j],f[i-w-1][que[head]]+que[head]*a[i].ap-j*a[i].ap); } head=1;tail=0; for(int j=Maxp;j>=0;j--) { while(head<=tail&&que[head]>a[i].bs+j)head++; while(head<=tail&&f[i-w-1][que[tail]]+que[tail]*a[i].bp<f[i-w-1][j]+j*a[i].bp)tail--; que[++tail]=j; if(head<=tail) f[i][j]=max(f[i][j],f[i-w-1][que[head]]+que[head]*a[i].bp-j*a[i].bp); } } cout<<f[n][0]<<endl; return 0; }
推这题式子的时候,我脑子总是不清晰,我把上面那个式子推出来了,但是看了好久,愣是不知道怎么个优化法
还是单调队列题目写少了吗
或者说其实我前面写过的题目就是没有完全的理解。。难绷