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

上一篇blog已经讲了单调队列与单调栈的用法,本篇将讲述如何借助单调队列优化dp。

我先丢一道题:bzoj1855

 

此题不难想出O(n^4)做法,我们用f[i][j]表示第i天手中持有j只股票时,所赚钱的最大值。

不难推出以下式子:

$f[i][j]=max\left\{
\begin{aligned}
f[k][l]+(l-j)\times bp[i] , l \in [j,j+bs[i]]\\
f[k][l]-(j-l)\times ap[i] , l \in [j-as[i],j]\\
\end{aligned}
\right \}
k \in [1,i-w]$

考虑到第i天持有的j只股票不一定全是第i天购买的,则对于$\forall j$,有$f[i][j]≥f[i-1][j]$,式子可化为O(n^3),变为:

$f[i][j]=max\left\{
\begin{aligned}
f[i-w-1][l]+(l-j)\times bp[i] , l \in [j,j+bs[i]]\\
f[i-w-1][l]-(j-l)\times ap[i] , l \in [j-as[i],j]\\
\end{aligned}
\right \}$

考虑到$i,j≤1000$,如采用此做法依然会TLE,我们考虑采用单调队列进行优化,以下以卖出股票举例:

我们设$k<l<j$,我们认为$f[i-w-1][k]$比$f[i-w-1][l]$优,则必然满足$f[i-w-1][k]>f[i-1-1][l]+(k-l) \times bp[i]$。

我们对于每一个$i$,维护一个$f[i-w-1]$的单调队列,采用上述的判定机制删除非最优元素,同时考虑到$k,l$应位于区间$[j,j+bs[i]]$中,则需从队头删除下标不位于该区间的元素,最优用队头元素更新f[i][j]即可。

 

买入同理。

 

 1 #include<bits/stdc++.h>
 2 #define M 4010
 3 using namespace std;
 4 int f[M][M/2]={0},ap[M]={0},bp[M]={0},as[M]={0},bs[M]={0};
 5 int t,n,w,head,tail,q[M]={0},id[M]={0};
 6 int main(){
 7     scanf("%d%d%d",&t,&n,&w);
 8     for(int i=w+1;i<=t+w;i++) scanf("%d%d%d%d",ap+i,bp+i,as+i,bs+i);
 9     for(int i=0;i<=w;i++)
10     for(int j=1;j<=n;j++) f[i][j]=-1234567890;
11     for(int i=w+1;i<=t+w;i++){
12         for(int j=0;j<=n;j++) f[i][j]=f[i-1][j];
13         head=tail=0;
14         for(int j=1;j<=n;j++){
15             if(head<tail&&id[head+1]<j-as[i]) head++;
16             while(head<tail&&q[tail]-f[i-w-1][j-1]<((j-1)-id[tail])*ap[i]) tail--;
17             q[++tail]=f[i-w-1][j-1]; id[tail]=j-1;
18             if(head<tail) f[i][j]=max(f[i][j],q[head+1]-(j-id[head+1])*ap[i]);
19         }
20         head=tail=0;
21         for(int j=n-1;j>=0;j--){
22             if(head<tail&&j+bs[i]<id[head+1]) head++;
23             while(head<tail&&f[i-w-1][j+1]-q[tail]>(id[tail]-(j+1))*bp[i]) tail--;
24             q[++tail]=f[i-w-1][j+1]; id[tail]=j+1;
25             if(head<tail) f[i][j]=max(f[i][j],q[head+1]+(id[head+1]-j)*bp[i]);
26         }
27     }
28     printf("%d\n",f[t+w][0]);
29 }

 

转载于:https://www.cnblogs.com/xiefengze1/p/8495754.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值