[SCOI2010]股票交易

洛谷题目链接:[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;
}
相关文章
相关标签/搜索