洛谷 P2569 [SCOI2010] 股票交易 题解

题目:

题目描述

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

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

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

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

输入格式

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

接下来 T 行,第 i 行代表第 �−1i1 天的股票走势,每行 44 个整数,分别表示 ���, ���, ���, ���APi, 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≤�<�≤50,1≤MaxP≤500W<T50,1MaxP50;
  • 对于 50%50% 的数据,0≤�<�≤2000,1≤MaxP≤500W<T2000,1MaxP50;
  • 对于 100%100% 的数据,0≤�<�≤2000,1≤MaxP≤20000W<T2000,1MaxP2000;
  • 对于所有的数据,1≤���≤���≤1000,1≤���,���≤MaxP1BPiAPi1000,1ASi,BSiMaxP

思路:

看到题目和数据范围<=2000,一眼dp

考虑状态定义,日期肯定为状态之一,

接着在持有股票数量和赚的钱中选其一

考虑到钱数可能很大,所以使用股票数作为状态

可得dp(i,j)->第i天时,持股数为j时最多赚的钱

状态满足无后效性

稍微思考,可得转移方程

买入:dp(i,j)=max(dp(k,p)-(j-p)*ap[i] (k∈{x|0<=x<=i-w},p∈{x|j-as[i]<=x<=j}))

卖出:dp(i,j)=max(dp(k,p)+(p-j)*bp[i] (k∈{x|0<=x<=i-w},p∈{x|j<=x<=j+bs[i]}))

发现暴力会T飞

考虑优化

首先,由(k∈{x|0<=x<=i-w},p∈{x|j<=x<=j+bs[i]})可以观察到我们维护的是一段连续区间里的最大值

那么考虑单调队列

有一个重要结论:只有股票数相同时,钱数才是可以比较的

所以我们要开MaxP维的单调队列,维护每个持股数时的最大赚钱

在过程中还要开两个单调队列,维护买入、卖出操作是的最优解

AC代码:

#include <bits/stdc++.h>
using namespace std;
#define int long long
const int N=2100,inf=1e9;
int T,n,w;
int ap[N],bp[N],as[N],bs[N];
struct node{
    int v,g,p;
};
deque <node>q[N];
deque <node>qa;
deque <node>qb;
int dp[N][N];
signed main(){
    cin>>T>>n>>w;
    for(int i=1;i<=T;i++){
        cin>>ap[i]>>bp[i]>>as[i]>>bs[i];
    }
    int ans=0;
    q[0].push_back({inf,0,0});
    for(int i=1;i<=T;i++){
        //for(int j=0;j<=n;j++) while(!q[j].empty() and q[j].front().p<i-w) q[j].pop_front();
        qa.clear();qb.clear();
        //mr
        for(int j=0;j<=n;j++){
            while(!qa.empty() and qa.front().g<j-as[i]) qa.pop_front();
            if(!q[j].empty()){
                node in=q[j].front();
                while(!qa.empty() and qa.back().v-(j-qa.back().g)*ap[i]<=in.v) qa.pop_back();
                qa.push_back(in);
            }
            if(!qa.empty()){
                node a=qa.front();
                dp[i][j]=max(a.v-(j-a.g)*ap[i],dp[i][j]);
            }
        }
        //mc
        for(int j=n;j>=0;j--){
            while(!qb.empty() and qb.front().g>j+bs[i]) qb.pop_front();
            if(!q[j].empty()){
                node in=q[j].front();
                while(!qb.empty() and qb.back().v+(qb.back().g-j)*bp[i]<=in.v) qb.pop_back();
                qb.push_back(in);
            }
            if(!qb.empty()){
                node b=qb.front();
                dp[i][j]=max(b.v+(b.g-j)*bp[i],dp[i][j]);
            }
        }
        if(i-w>=0){
            for(int j=0;j<=n;j++){
                while(!q[j].empty() and q[j].back().v<=dp[i-w][j]) q[j].pop_back();
                q[j].push_back({dp[i-w][j],j,i});
                ans=max(ans,dp[i][j]);
            }
        }
    }
    cout<<ans-inf<<endl;
    
    return 0;
}

posted @ 2024-08-15 12:17  AIRSDREAM  阅读(72)  评论(0)    收藏  举报