• [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;
    }
    
  • 相关阅读:
    JavaScript中对事件简单的理解
    正则表达式 RE模块
    模块
    面向对象进阶
    元类详细解释
    四.面向对象和函数补充
    四.函数
    Python的基础知识:
    五层协议及tcp三次握手四次挥手
    nginx常见错误
  • 原文地址:https://www.cnblogs.com/hhh1109/p/10667088.html
Copyright © 2020-2023  润新知