【单调队列优化DP】BZOJ1855-[Scoi2010]股票交易

【题目大意】

  已知第i天的股票买入价为每股APi,第i天的股票卖出价为每股BPi(数据保证对于每个i,都有APi>=BPi),第i天的一次买入至多只能购买ASi股,一次卖出至多只能卖出BSi股。 股票交易所规定在两次交易(某一天的买入或者卖出均算是一次交易)之间,至少要间隔W天,也就是说如果在第i天发生了交易,那么从第i+1天到第i+W天,均不能发生交易。同时,在任何时间,一个人的手里的股票数不能超过MaxP。 在第1天之前,有一大笔钱(可以认为钱的数目无限),没有任何股票,求T天之后最多赚到多少钱?

【思路】

f[i][j]表示表示到第i个交易日手中持有至多j股时的最大收益。

1、从前一天不买不卖:f[i][j]=max(f[i-1][j],f[i][j])

2、从i-W-1天买股:f[i][j]=max(f[i-W-1][k]-(j-k)*AP[i],f[i][j])

  f[i][j]=max(f[i-W-1][k]+k*AP[i])-j*AP[i]

   令g[i-W-1][k]=f[i-W-1][k]+k*AP[i] → f[i][j]=max(g[i-W-1][k]) - j*AP[i]

3、从i-W-1天卖股:f[i][j]=max(f[i-W-1][k]+(k-j)*BP[i],f[i][j])

  f[i][j]=max(f[i-W-1][k]+k*BP[i])-j*BP[i]。

      令g'[i-W-1][k]=f[i-W-1][k]+k*BP[i] → f[i][j]=max(g'[i-W-1][k]) - j*BP[i]

由于对于g[i-W-1][j]与g'[i-W-1][j]均满足:若j1>j2且g[i-W-1][j1]>g[i-W-1][j2],则不必保留g[i-W-1][j2]。所以可以用单调队列来进行优化。

#关于初始化#f[0][0]=0,对于1~W+1天,仅存在买入操作,初始值为-AP[i]*j。

 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #define pre i-W-1
 6 #define INF 0x7fffffff
 7 using namespace std;
 8 const int MAXN=2000+5;
 9 struct node
10 {
11     int f,pos;    
12 };
13 int T,MaxP,W;
14 int AP[MAXN],BP[MAXN],AS[MAXN],BS[MAXN];
15 int f[MAXN][MAXN];//表示到第i个交易日手中持有j股时的最大收益
16 node q[MAXN];
17 
18 void init()
19 {
20     scanf("%d%d%d",&T,&MaxP,&W);
21     for (int i=1;i<=T;i++) scanf("%d%d%d%d",&AP[i],&BP[i],&AS[i],&BS[i]);
22 }
23 
24 void dp()
25 {
26     memset(f,128,sizeof(f));
27     for(int i=0;i<=W+1;i++)
28     {
29         for(int j=0;j<=(min(MaxP,AS[i]));j++)
30             f[i][j]=-AP[i]*j;//表示前(w+1)天仅有可能进行买入操作 
31     }
32     f[0][0]=0; 
33     for (int i=1;i<=T;i++)
34     {
35         for (int j=0;j<=MaxP;j++) f[i][j]=max(f[i][j],f[i-1][j]);
36         if (pre>0)
37         {
38             int head=0,tail=0;
39             for (int j=0;j<=MaxP;j++)
40             {
41                 int nowf=f[pre][j]+AP[i]*j;
42                 while (head<tail && q[tail-1].f<nowf) tail--;
43                 q[tail++]=(node){nowf,j};
44                 while (head<tail && q[head].pos<j-AS[i]) head++;
45                 f[i][j]=max(f[i][j],q[head].f-AP[i]*j);
46             }
47             
48             head=0,tail=0;
49             for (int j=MaxP;j>=0;j--)
50             {
51                 int nowf=f[pre][j]+BP[i]*j;
52                 while (head<tail && q[tail-1].f<nowf) tail--;
53                 q[tail++]=(node){nowf,j};
54                 while (head<tail && q[head].pos>j+BS[i]) head++;
55                 f[i][j]=max(f[i][j],q[head].f-BP[i]*j);
56             }
57         }
58     }
59 }
60 
61 void getans()
62 {
63     int ans=-INF;
64     for (int i=0;i<=MaxP;i++) ans=max(ans,f[T][i]);
65     printf("%d
",ans);
66 }
67 
68 int main()
69 {
70     init();
71     dp();
72     getans();
73     return 0;
74 } 
原文地址:https://www.cnblogs.com/iiyiyi/p/5449579.html