[SCOI2010] 股票交易

发布时间 2023-11-22 17:57:47作者: HL_ZZP

题目描述

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

通过一段时间的观察,lxhgwwlxhgww 预测到了未来 TT 天内某只股票的走势,第 ii 天的股票买入价为每股 APiAPi,第 ii 天的股票卖出价为每股 BPiBPi(数据保证对于每个 ii,都有 APi≥BPiAPiBPi),但是每天不能无限制地交易,于是股票交易所规定第 ii 天的一次买入至多只能购买 ASiASi 股,一次卖出至多只能卖出 BSiBSi 股。

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

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

输入格式

输入数据第一行包括 33 个整数,分别是 TT,MaxPMaxP,WW。

接下来 TT 行,第 ii 行代表第 i−1i1 天的股票走势,每行 44 个整数,分别表示 APi, BPi, ASi, BSiAPi, BPi, ASi, BSi

输出格式

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

输入输出样例

输入 #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%30% 的数据,0≤W<T≤50,1≤MaxP≤500W<T50,1MaxP50;
  • 对于 50%50% 的数据,0≤W<T≤2000,1≤MaxP≤500W<T2000,1MaxP50;
  • 对于 100%100% 的数据,0≤W<T≤2000,1≤MaxP≤20000W<T2000,1MaxP2000;
  • 对于所有的数据,1≤BPi≤APi≤1000,1≤ASi,BSi≤MaxP1BPiAPi1000,1ASi,BSiMaxP。

 

 额,化完的式子长这样,然后就直接单调队列优化就好了

#include<bits/stdc++.h>
#define ll long long
using namespace std;
inline int read() {
    char c=getchar();int a=0,b=1;
    for(;c<'0'||c>'9';c=getchar())if(c=='-')b=-1;
    for(;c>='0'&&c<='9';c=getchar())a=a*10+c-48;return a*b;
}
int n,w,f[2001][2001],Maxp;
struct rec
{
    int ap,bp,as,bs;
}a[2001];
int que[2001],head,tail;
int main()
{
//    freopen(".in","r",stdin);
//    freopen(".out","w",stdout);
    n=read();Maxp=read(),w=read();
    for(int i=1;i<=n;i++)
    {
        a[i].ap=read();
        a[i].bp=read();
        a[i].as=read();
        a[i].bs=read();
    }
    memset(f,128,sizeof(f));
    for(int i=1;i<=n;i++)
    {
        head=1;tail=0;
        for(int j=0;j<=a[i].as;j++)
        {
            f[i][j]=-1*a[i].ap*j;
        }
        for(int j=0;j<=Maxp;j++)
        {
            f[i][j]=max(f[i][j],f[i-1][j]);
        }
        if(i<=w)continue;
        for(int j=0;j<=Maxp;j++)
        {
            while(head<=tail&&que[head]<j-a[i].as)head++;
            while(head<=tail&&f[i-w-1][j]+j*a[i].ap>=f[i-w-1][que[tail]]+que[tail]*a[i].ap)tail--;
            que[++tail]=j;
            if(head<=tail)
            f[i][j]=max(f[i][j],f[i-w-1][que[head]]+que[head]*a[i].ap-j*a[i].ap);
        }
        head=1;tail=0;
        for(int j=Maxp;j>=0;j--)
        {
            while(head<=tail&&que[head]>a[i].bs+j)head++;
            while(head<=tail&&f[i-w-1][que[tail]]+que[tail]*a[i].bp<f[i-w-1][j]+j*a[i].bp)tail--;
            que[++tail]=j;
            if(head<=tail)
            f[i][j]=max(f[i][j],f[i-w-1][que[head]]+que[head]*a[i].bp-j*a[i].bp);
        }
    }
    cout<<f[n][0]<<endl;
    return 0;
}

推这题式子的时候,我脑子总是不清晰,我把上面那个式子推出来了,但是看了好久,愣是不知道怎么个优化法
还是单调队列题目写少了吗
或者说其实我前面写过的题目就是没有完全的理解。。难绷