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

P2569 [SCOI2010]股票交易

题目描述

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

通过一段时间的观察,( ext{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)天,均不能发生交易。同时,为了避免垄断,股票交易所还规定在任何时间,一个人的手里的股票数不能超过 ( ext{MaxP})

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

输入输出格式

输入格式:

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

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

输出格式:

输出数据为一行,包括 (1) 个数字,表示 ( ext{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\%) 的数据,(0leq W<Tleq 50,1leq ext{MaxP}leq50)
对于 (50\%) 的数据,(0leq W<Tleq 2000,1leq ext{MaxP}leq50)
对于 (100\%) 的数据,(0leq W<Tleq 2000,1leq ext{MaxP}leq2000)
对于所有的数据,(1leq BP_ileq AP_ileq 1000,1leq AS_i,BS_ileq ext{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;
}
原文地址:https://www.cnblogs.com/hhh1109/p/10667088.html