当前位置: 代码迷 >> 综合 >> 【洛谷_P2569】股票交易
  详细解决方案

【洛谷_P2569】股票交易

热度:95   发布时间:2024-02-10 08:00:02.0

股票交易


题目描述

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

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

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

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

输入格式

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

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

输出格式

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

输入输出样例

输入

5 2 0
2 1 1 1
2 1 1 1
3 2 1 1
4 3 1 1
5 4 1 1

输出

3

解题思路

模拟在每一天中,买股和卖股的情况,动态转移方程为:

f[i][j]=max(max(f[k][j])-j*a[i]);//{j<=as[i],i>w+1}

如果就这么简单的话,那我说这句话有什么意义?我们还要用单调队列维护这里面的最大值,那么程序就出来了:

#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;int e,f[2010][2010],q[100010][3];
int a[2010],b[2010],sa[2010],sb[2010];
int w,t,maxp;int max(int x,int y)
{if(x>y)return x;return y;
}int main()
{scanf("%d",&e);while(e--){scanf("%d%d%d",&t,&maxp,&w);memset(f,-0x3f3f3f3f,sizeof(f));for(int i=1;i<=t;i++)scanf("%d%d%d%d",&a[i],&b[i],&sa[i],&sb[i]);for(int i=1;i<=w+1;i++)for(int j=0;j<=sa[i]&&j<=maxp;j++)f[i][j]=-j*a[i];for(int i=1;i<=t;i++){for(int j=0;j<=maxp;j++)f[i][j]=max(f[i][j],f[i-1][j]);int hd=1,tl=0;if(i<=w+1) continue;int s=i-w-1;for(int j=0;j<=maxp;j++){int sum=f[s][j]+j*a[i];while(hd<=tl&&sum>q[tl][2]) tl--;q[++tl][1]=j;q[tl][2]=sum;while(hd<=tl&&j-q[hd][1]>sa[i]) hd++;f[i][j]=max(f[i][j],q[hd][2]-j*a[i]);}hd=1,tl=0;for(int j=maxp;j>=0;j--){int sum=f[s][j]+j*b[i];while(hd<=tl&&sum>q[tl][2]) tl--;q[++tl][1]=j;q[tl][2]=sum;while(hd<=tl&&q[hd][1]-j>sb[i]) hd++;f[i][j]=max(f[i][j],q[hd][2]-j*b[i]);}}int ans=0; for(int i=0;i<=maxp;i++)ans=max(ans,f[t][i]);cout<<ans<<endl;}return 0;
}