[dp][单调队列] Jzoj P2569 股票交易

题目描述

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

通过一段时间的观察,\text{lxhgww}lxhgww 预测到了未来 TT 天内某只股票的走势,第 ii 天的股票买入价为每股 AP_iAPi,第 ii 天的股票卖出价为每股 BP_iBPi(数据保证对于每个 ii,都有 AP_i \geq BP_iAPiBPi),但是每天不能无限制地交易,于是股票交易所规定第 ii 天的一次买入至多只能购买 AS_iASi 股,一次卖出至多只能卖出 BS_iBSi 股。

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

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

输入输出格式

输入格式:

 

输入数据第一行包括 33 个整数,分别是 TT,\text{MaxP}MaxP,WW。

接下来 TT 行,第 ii 行代表第 i-1i1 天的股票走势,每行 44 个整数,分别表示 AP_i,\ BP_i,\ AS_i,\ BS_iAPi, BPi, ASi, BSi

 

输出格式:

 

输出数据为一行,包括 11 个数字,表示 \text{lxhgww}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\%30% 的数据,0\leq W<T\leq 50,1\leq\text{MaxP}\leq500W<T50,1MaxP50

对于 50\%50% 的数据,0\leq W<T\leq 2000,1\leq\text{MaxP}\leq500W<T2000,1MaxP50

对于 100\%100% 的数据,0\leq W<T\leq 2000,1\leq\text{MaxP}\leq20000W<T2000,1MaxP2000

对于所有的数据,1\leq BP_i\leq AP_i\leq 1000,1\leq AS_i,BS_i\leq\text{MaxP}1BPiAPi1000,1ASi,BSiMaxP

题解

  • 其实这题可以用dp来做,设f[i][j]为第i天拥有数量为j的股票能赚的最大金额
  • 那么转移其实很显然,有四种情况
  • ①凭空买,f[i][j]=-j*ap
  • ②不买不卖,f[i][j]=max(f[i][j-1],f[i][j])
  • ③在之前的基础上买,f[i][j]=max(f[i][j],f[i-w-1][k]-(j-k)*ap)
  • 为什么只有i-w-1呢,因为i-w-2其实在第二种情况时候已经转移到i-w-1了,所以可以只做i-w-1
  • ④在之前的基础上卖,f[i][j]=max(f[i][j],f[i-w-1][k]+(k-j)*bp)
  • 那么怎么用单调队列优化呢,考虑一下直接dp是三次方的,要做到二次方
  • 三四的情况的式子,f[i][j]=max(f[i][j],f[i-w-1][k]-j*ap+k*ap),f[i][j]=max(f[i][j],f[i-w-1][k]-j*ap)+k*ap
  • 第四种情况也是类似的,那么这样的话可以发现,其实就是在找一个滑动窗口的最大值
  • 显然可以单调队列

代码

 1 #include <cstdio>
 2 #include <iostream>
 3 #include <cstring>
 4 using namespace std;
 5 int n,m,w,ans,f[2010][2010],Q[2010];
 6 int main()
 7 {
 8     scanf("%d%d%d",&n,&m,&w);
 9     memset(f,128,sizeof(f));
10     for (int i=1,ap,bp,as,bs;i<=n;i++)    
11     {
12         scanf("%d%d%d%d",&ap,&bp,&as,&bs);
13         for (int j=0;j<=as;j++) f[i][j]=-ap*j;
14         for (int j=0;j<=m;j++) f[i][j]=max(f[i][j],f[i-1][j]);
15         if (i<=w) continue;
16         int head=1,tail=0;
17         for (int j=0;j<=m;j++)
18         {
19             while (head<=tail&&Q[head]<j-as) head++;
20             while (head<=tail&&f[i-w-1][Q[tail]]+Q[tail]*ap<=f[i-w-1][j]+j*ap) tail--;
21             Q[++tail]=j;
22             if (head<=tail) f[i][j]=max(f[i][j],f[i-w-1][Q[head]]+Q[head]*ap-j*ap);
23         }
24         head=1; tail=0;
25         for (int j=m;j>=0;j--)
26         {
27             while (head<=tail&&Q[head]>j+bs) head++;
28             while (head<=tail&&f[i-w-1][Q[tail]]+Q[tail]*bp<=f[i-w-1][j]+j*bp) tail--;
29             Q[++tail]=j;
30             if (head<=tail) f[i][j]=max(f[i][j],f[i-w-1][Q[head]]+Q[head]*bp-j*bp);
31         }
32     }
33     for (int i=0;i<=m;i++) ans=max(ans,f[n][i]);
34     printf("%d",ans);
35 }

 

posted @ 2018-10-27 08:34  BEYang_Z  阅读(238)  评论(0编辑  收藏  举报