• [SCOI2010]股票交易


    洛谷题目连接:[SCOI2010]股票交易

    题目描述

    最近lxhgww又迷上了投资股票,通过一段时间的观察和学习,他总结出了股票行情的一些规律。

    通过一段时间的观察,lxhgww预测到了未来T天内某只股票的走势,第i天的股票买入价为每股APi,第i天的股票卖出价为每股BPi(数据保证对于每个i,都有APi>=BPi),但是每天不能无限制地交易,于是股票交易所规定第i天的一次买入至多只能购买ASi股,一次卖出至多只能卖出BSi股。

    另外,股票交易所还制定了两个规定。为了避免大家疯狂交易,股票交易所规定在两次交易(某一天的买入或者卖出均算是一次交易)之间,至少要间隔W天,也就是说如果在第i天发生了交易,那么从第i+1天到第i+W天,均不能发生交易。同时,为了避免垄断,股票交易所还规定在任何时间,一个人的手里的股票数不能超过MaxP。

    在第1天之前,lxhgww手里有一大笔钱(可以认为钱的数目无限),但是没有任何股票,当然,T天以后,lxhgww想要赚到最多的钱,聪明的程序员们,你们能帮助他吗?

    输入输出格式

    输入格式:

    输入数据第一行包括3个整数,分别是T,MaxP,W。

    接下来T行,第i行代表第i-1天的股票走势,每行4个整数,分别表示APi,BPi,ASi,BSi。

    输出格式:

    输出数据为一行,包括1个数字,表示lxhgww能赚到的最多的钱数。

    输入输出样例

    输入样例#1:

    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

    一句话题意: 每天最多可以买进(as_i)张股票,卖出(bs_i)张股票,但是每个时刻手中的票最多都只能有(maxp)张,每买入一张股票可以获得(ap_i)元,卖出一张股票可以获得(bp_i)元,且如果第(i)天进行了交易,那么从第(i+1)到第(i+w)天都不能再进行交易,问到第(n)天最多可以获得的价值.

    题解: 这个数据范围显然是能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
    ", f[n][0]);
        return 0;
    }
    
  • 相关阅读:
    CVS 快速入门指南
    我的博客皮肤
    OOP三个基本特征
    vi 操作
    智者能堪破这世界的定数,但没人能逃脱劫数
    技术路径的四阶段
    python每日学习2018/1/14(python之禅)
    python每日学习2018/1/11
    Python PyInstaller安装和使用教程(详解版)
    Windows环境下安装MinGW/gcc
  • 原文地址:https://www.cnblogs.com/BCOI/p/9133358.html
Copyright © 2020-2023  润新知