[luogu] P2569 [SCOI2010]股票交易 (单调队列优化)

P2569 [SCOI2010]股票交易

题目描述

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

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

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

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

输入输出格式

输入格式:

输入数据第一行包括 \(3\) 个整数,分别是 \(T\)\(\text{MaxP}\)\(W\)

接下来 \(T\) 行,第 \(i\) 行代表第 \(i-1\) 天的股票走势,每行 \(4\) 个整数,分别表示 \(AP_i,\ BP_i,\ AS_i,\ BS_i\)

输出格式:

输出数据为一行,包括 \(1\) 个数字,表示 \(\text{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\leq W<T\leq 50,1\leq\text{MaxP}\leq50\)
对于 \(50\%\) 的数据,\(0\leq W<T\leq 2000,1\leq\text{MaxP}\leq50\)
对于 \(100\%\) 的数据,\(0\leq W<T\leq 2000,1\leq\text{MaxP}\leq2000\)
对于所有的数据,\(1\leq BP_i\leq AP_i\leq 1000,1\leq AS_i,BS_i\leq\text{MaxP}\)

题解

可以说下面这篇博客写的算是非常好了。
sooke关于本题的题解

Code

#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
using namespace std;
const int N=3e3+5;
int f[N][N];
int as[N],ap[N],bs[N],bp[N];
int n,maxp,w,q[N];
int read(){
    int x=0,w=1;char ch=getchar();
    while(ch>'9'||ch<'0'){if(ch=='-')w=-1;ch=getchar();}
    while(ch>='0'&&ch<='9')x=x*10+ch-'0',ch=getchar();
    return x*w;
}

int main(){
    n=read();maxp=read();w=read();
    memset(f,128,sizeof(f));
    for(int i=1;i<=n;i++){
        ap[i]=read();bp[i]=read();
        as[i]=read();bs[i]=read();
        for(int j=0;j<=as[i];j++)
        f[i][j]=-j*ap[i];
    }
    for(int i=1;i<=n;i++){
        for(int j=0;j<=maxp;j++)
        f[i][j]=max(f[i-1][j],f[i][j]);
        if(i<=w)continue;
        int h=1,t=0;
        for(int j=0;j<=maxp;j++){
            while(h<=t&&q[h]<j-as[i])h++;
            while(h<=t&&f[i-w-1][q[t]]+q[t]*ap[i]<=f[i-w-1][j]+j*ap[i])t--;
            q[++t]=j; if(h<=t)	f[i][j]=max(f[i][j],f[i-w-1][q[h]]+q[h]*ap[i]-ap[i]*j);
        }h=1;t=0;
        for(int j=maxp;j>=0;j--){
            while(h<=t&&q[h]>j+bs[i])h++;
            while(h<=t&&f[i-w-1][q[t]]+q[t]*bp[i]<=f[i-w-1][j]+j*bp[i])t--;
            q[++t]=j; if(h<=t)	f[i][j]=max(f[i][j],f[i-w-1][q[h]]+q[h]*bp[i]-bp[i]*j);
        }
    }
    cout<<f[n][0]<<endl;
    return 0;
}
posted @ 2019-04-07 21:08  Epiphyllum_thief  阅读(151)  评论(0编辑  收藏  举报