洛谷 P2569 [SCOI2010] 股票交易 题解
题目:
题目描述
最近 lxhgwwlxhgww 又迷上了投资股票,通过一段时间的观察和学习,他总结出了股票行情的一些规律。
通过一段时间的观察,lxhgwwlxhgww 预测到了未来 �T 天内某只股票的走势,第 �i 天的股票买入价为每股 ���APi,第 �i 天的股票卖出价为每股 ���BPi(数据保证对于每个 �i,都有 ���≥���APi≥BPi),但是每天不能无限制地交易,于是股票交易所规定第 �i 天的一次买入至多只能购买 ���ASi 股,一次卖出至多只能卖出 ���BSi 股。
另外,股票交易所还制定了两个规定。为了避免大家疯狂交易,股票交易所规定在两次交易(某一天的买入或者卖出均算是一次交易)之间,至少要间隔 �W 天,也就是说如果在第 �i 天发生了交易,那么从第 �+1i+1 天到第 �+�i+W 天,均不能发生交易。同时,为了避免垄断,股票交易所还规定在任何时间,一个人的手里的股票数不能超过 MaxPMaxP。
在第 11 天之前,lxhgwwlxhgww 手里有一大笔钱(可以认为钱的数目无限),但是没有任何股票,当然,�T 天以后,lxhgwwlxhgww 想要赚到最多的钱,聪明的程序员们,你们能帮助他吗?
输入格式
输入数据第一行包括 33 个整数,分别是 �T,MaxPMaxP,�W。
接下来 �T 行,第 �i 行代表第 �−1i−1 天的股票走势,每行 44 个整数,分别表示 ���, ���, ���, ���APi, BPi, ASi, BSi。
输出格式
输出数据为一行,包括 11 个数字,表示 lxhgwwlxhgww 能赚到的最多的钱数。
输入输出样例
5 2 0
2 1 1 1
2 1 1 1
3 2 1 1
4 3 1 1
5 4 1 1
3
说明/提示
- 对于 30%30% 的数据,0≤�<�≤50,1≤MaxP≤500≤W<T≤50,1≤MaxP≤50;
- 对于 50%50% 的数据,0≤�<�≤2000,1≤MaxP≤500≤W<T≤2000,1≤MaxP≤50;
- 对于 100%100% 的数据,0≤�<�≤2000,1≤MaxP≤20000≤W<T≤2000,1≤MaxP≤2000;
- 对于所有的数据,1≤���≤���≤1000,1≤���,���≤MaxP1≤BPi≤APi≤1000,1≤ASi,BSi≤MaxP
思路:
看到题目和数据范围<=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;
}
浙公网安备 33010602011771号