BZOJ1855: [Scoi2010]股票交易

Description

最近lxhgww又迷上了投资股票,通过一段时间的观察和学习,他总结出了股票行情的一些规律。 通过一段时间的观察,lxhgww预测到了未来T天内某只股票的走势,第i天的股票买入价为每股APi,第i天的股票卖出价为每股BPi(数据保证对于每个i,都有APi>=BPi),但是每天不能无限制地交易,于是股票交易所规定第i天的一次买入至多只能购买ASi股,一次卖出至多只能卖出BSi股。 另外,股票交易所还制定了两个规定。为了避免大家疯狂交易,股票交易所规定在两次交易(某一天的买入或者卖出均算是一次交易)之间,至少要间隔W天,也就是说如果在第i天发生了交易,那么从第i+1天到第i+W天,均不能发生交易。同时,为了避免垄断,股票交易所还规定在任何时间,一个人的手里的股票数不能超过MaxP。 在第1天之前,lxhgww手里有一大笔钱(可以认为钱的数目无限),但是没有任何股票,当然,T天以后,lxhgww想要赚到最多的钱,聪明的程序员们,你们能帮助他吗?

Input

输入数据第一行包括3个整数,分别是T,MaxP,W。 接下来T行,第i行代表第i-1天的股票走势,每行4个整数,分别表示APi,BPi,ASi,BSi。

Output

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

Sample Input

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

Sample Output

3

HINT

对于30%的数据,0<=W<T<=50,1<=MaxP<=50
对于50%的数据,0<=W<T<=2000,1<=MaxP<=50
对于100%的数据,0<=W<T<=2000,1<=MaxP<=2000
对于所有的数据,1<=BPi<=APi<=1000,1<=ASi,BSi<=MaxP

 

怎么感觉做单调队列优化着优化着没找到感觉结果巨***儿模糊??

一眼方程f[i][j]表示第i天手里有j张股票,三种转移:

考虑优化,上下界单调,单调队列

然后推柿子,把固定项i提出来,然后剩下的分两种情况讨论即可(雾??复杂度O(nm)

代码如下:

 1 //MT_LI
 2 #include<cmath>
 3 #include<cstdio>
 4 #include<cstring>
 5 #include<cstdlib>
 6 #include<algorithm>
 7 using namespace std;
 8 int f[2100][2100];//表示第i天手里有j套股票的最优策略
 9 /*
10 不买不卖    f[i][j]=f[i-1][j]
11     买入    f[i][j]=f[i-w-1][k]-ap[i]*(j-k)|k>=j-as
12             f[i][j]=f[i-w-1][k]-ap[i]*j+ap[i]*k
13             
14     卖出     f[i][j]=f[i-w-1][k]+bp[i]*(k-j)|k<=j+bs
15 */ 
16 struct node{
17     int ap,bp,as,bs;
18 }a[4100];int n,m,w;
19 int head,tail;
20 struct line{
21     int pos,x;
22 }list[4100];
23 int main()
24 {
25     scanf("%d%d%d",&n,&m,&w);
26     for(int i=1;i<=n;i++)scanf("%d%d%d%d",&a[i].ap,&a[i].bp,&a[i].as,&a[i].bs);
27     for(int i=1;i<=m;i++)f[0][i]=-99999999;
28     for(int i=1;i<=n;i++)
29     {
30         head=1,tail=0;
31         for(int j=0;j<=m;j++)
32         {
33             f[i][j]=f[i-1][j];
34             if(i<=w){if(j<=a[i].as)f[i][j]=max(f[i][j],-j*a[i].ap);continue;}
35             while(head<=tail&&list[head].pos<j-a[i].as)head++;
36             if(head<=tail)f[i][j]=max(f[i][j],list[head].x-a[i].ap*j);
37             while(head<=tail&&list[tail].x<f[i-w-1][j]+a[i].ap*j)tail--;
38             list[++tail].x=f[i-w-1][j]+a[i].ap*j;
39             list[tail].pos=j;
40         }
41         head=1,tail=0;
42         if(i>w)
43         {
44             for(int j=m;j>=0;j--)
45             {
46                 while(head<=tail&&list[head].pos>j+a[i].bs)head++;
47                 if(head<=tail)f[i][j]=max(f[i][j],list[head].x-a[i].bp*j);
48                 while(head<=tail&&list[tail].x<f[i-w-1][j]+a[i].bp*j)tail--;
49                 list[++tail].x=f[i-w-1][j]+a[i].bp*j;
50                 list[tail].pos=j;
51             }
52         }
53     }
54     printf("%d\n",f[n][0]);
55     return 0;
56 }

 

posted @ 2018-09-14 21:45  MT_LI  阅读(142)  评论(0编辑  收藏  举报