洛谷题目链接:[SCOI2010]股票交易
题目描述
最近lxhgww又迷上了投资股票,经过一段时间的观察和学习,他总结出了股票行情的一些规律。c++
经过一段时间的观察,lxhgww预测到了将来T天内某只股票的走势,第i天的股票买入价为每股APi,第i天的股票卖出价为每股BPi(数据保证对于每一个i,都有APi>=BPi),可是天天不能无限制地交易,因而股票交易所规定第i天的一次买入至多只能购买ASi股,一次卖出至多只能卖出BSi股。程序员
另外,股票交易所还制定了两个规定。为了不你们疯狂交易,股票交易所规定在两次交易(某一天的买入或者卖出均算是一次交易)之间,至少要间隔W天,也就是说若是在第i天发生了交易,那么从第i+1天到第i+W天,均不能发生交易。同时,为了不垄断,股票交易所还规定在任什么时候间,一我的的手里的股票数不能超过MaxP。学习
在第1天以前,lxhgww手里有一大笔钱(能够认为钱的数目无限),可是没有任何股票,固然,T天之后,lxhgww想要赚到最多的钱,聪明的程序员们,大家能帮助他吗?优化
输入输出格式
输入格式:url
输入数据第一行包括3个整数,分别是T,MaxP,W。spa
接下来T行,第i行表明第i-1天的股票走势,每行4个整数,分别表示APi,BPi,ASi,BSi。.net
输出格式:code
输出数据为一行,包括1个数字,表示lxhgww能赚到的最多的钱数。队列
输入输出样例
输入样例#1:ci
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
说明
对于30%的数据,0<=W<T<=50,1<=MaxP<=50
对于50%的数据,0<=W<T<=2000,1<=MaxP<=50
对于100%的数据,0<=W<T<=2000,1<=MaxP<=2000
对于全部的数据,1<=BPi<=APi<=1000,1<=ASi,BSi<=MaxP </br>
一句话题意: 天天最多能够买进$as_i$张股票,卖出$bs_i$张股票,可是每一个时刻手中的票最多都只能有$maxp$张,每买入一张股票能够得到$ap_i$元,卖出一张股票能够得到$bp_i$元,且若是第$i$天进行了交易,那么从第$i+1$到第$i+w$天都不能再进行交易,问到第$n$天最多能够得到的价值. </br>
题解: 这个数据范围显然是能DP的.咱们先想一下状态该如何定义.
首先根据这个状态转移的条件,有交易的天数限制,因此显然是须要一维来存交易到第几天的.而后是对于手中持有的股票数量的限制,显然至少是须要一重循环来枚举目前手中持有的股票数量的,因此考虑将这个也加入状态中.可得状态$f[i][j]$表示到第$i$天手中持有$j$张股票的最大利益.那么最后的答案就是 $f[n][0]$,由于显然在最后一天把全部股票都卖出不会比留着股票差.
而后想一下如何转移这个状态.那么从上一个状态到如今的状态$f[i][j]$,显然只有这几种状况:
- 第$i-1$天没有买/卖股票,第$i$天的最大收益为$f[i-1][j]$.
- 第$i-w-1$天进行了股票的买卖且拥有$k(k<j)$张股票,第$i$天有股票$j$张,此时买入了$j-k$张股票,可得最大收益为$f[i][j] = max(f[i][j], f[i-w-1][k]-(j-k)*ap[i])$
- 第$i-w-1$天进行了股票的买卖且拥有$k(k>j)$张股票,第$i$天有股票$j$张,此时卖出了$k-j$张股票,可得最大收益为$f[i][j]=max(f[i][j], f[i-w-1][k]+(k-j)*bp[i])$
此外没有别的转移方式了,因此能够列出状态转移方程.
那么考虑了状态转移以后,仔细想一想发现这个时间复杂度是$O(T*maxp^2)$的,显然这样是不能过100%的数据的.因此须要使用一些优化.
这里咱们将这个状态转移方程展开一下,发现: $$f[i-w-1][k]+(k-j)×bp[i]=(f[i-w-1][k]+k×bp[i])-j×bp[i]$$ 也就是说,在枚举了$i,j$的状况下,$i,j$是能够看作常数的,那么此时对答案有影响的就只有$k$了 .而且咱们发现, 若是$j$是以正确的顺序枚举的,那么$k$也就是逐渐在平移的了.好比说买入股票,那么拥有的股票也就会愈来愈多,卖出的话拥有的股票就会愈来愈少,事实上这个是符合 单调队列优化的条件的,因此咱们能够考虑将目前拥有的股票数存入单调队列中,优化后复杂度为$O(T*maxp)$.
固然分开和卖出的两种状况是要分开使用队列的,由于他们各自具备单调性,可是合起来并无.
#include<bits/stdc++.h> using namespace std; const int N=2000+5; int n, maxp, w, ap[N], bp[N], as[N], bs[N], ans = 0; int f[N][N], h1, h2, t1, t2, q1[N], q2[N]; int main(){ cin >> n >> maxp >> w; for(int i=1;i<=n;i++) cin >> ap[i] >> bp[i] >> as[i] >> bs[i]; memset(f, 128, sizeof(f)); f[0][0] = 0; for(int i=1;i<=n;i++){ for(int j=0;j<=maxp;j++) f[i][j] = max(f[i][j], f[i-1][j]); for(int j=0;j<=as[i];j++) f[i][j] = max(f[i][j], -1*j*ap[i]); if(i <= w) continue; h1 = h2 = 1, t1 = t2 = 0; for(int j=0;j<=maxp;j++){ while(h1 <= t1 && f[i-w-1][q1[t1]]-ap[i]*(j-q1[t1]) <= f[i-w-1][j]) t1--; while(h1 <= t1 && j-q1[h1] > as[i]) h1++; q1[++t1] = j; if(h1 <= t1) f[i][j] = max(f[i][j], f[i-w-1][q1[h1]]-(j-q1[h1])*ap[i]); } h1 = h2 = 1, t1 = t2 = 0; for(int j=maxp;j>=0;j--){ while(h2 <= t2 && f[i-w-1][q2[t2]]+bp[i]*(q2[t2]-j) <= f[i-w-1][j]) t2--; while(h2 <= t2 && q2[h2]-j > bs[i]) h2++; q2[++t2] = j; if(h2 <= t2) f[i][j] = max(f[i][j], f[i-w-1][q2[h2]]+(q2[h2]-j)*bp[i]); } } printf("%d\n", f[n][0]); return 0; }