单调队列优化DP

Posted oieredsion

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了单调队列优化DP相关的知识,希望对你有一定的参考价值。

维护一段连续区间的极值并且快速取出 用双端队列维护单调的序列

下面来到例题目

最近lxhgww又迷上了投资股票,通过一段时间的观察和学习,他总结出了股票行情的一些规律。
  通过一段时间的观察,lxhgww预测到了未来T天内某只股票的走势,第i天的股票买入价为每股APi,第i天的股票卖出价为每股BPi(数据保证对于每个i,都有APi>=BPi),但是每天不能无限制地交易,于是股票交易所规定第i天的一次买入至多只能购买ASi股,一次卖出至多只能卖出BSi股。
  另外,股票交易所还制定了两个规定。为了避免大家疯狂交易,股票交易所规定在两次交易(某一天的买入或者卖出均算是一次交易)之间,至少要间隔W天,也就是说如果在第i天发生了交易,那么从第i+1天到第i+W天,均不能发生交易。同时,为了避免垄断,股票交易所还规定在任何时间,一个人的手里的股票数不能超过MaxP。
  在第1天之前,lxhgww手里有一大笔钱(可以认为钱的数目无限),但是没有任何股票,当然,T天以后,lxhgww想要赚到最多的钱,聪明的程序员们,你们能帮助他吗?
解:
背包问题
定义f[i][j]表示i天持有j股票 所获得的最大收益 第i天不一定要买
所以方程转移为
\(f[i][j]=max(f[i-w-1][k]+(k-j)*b,f[i-w-1][k]-(j-k)*a,f[i-1][j]);\)
然后提取常数
注意到k的范围为$ [j,j+b[i]] 和[j-a[i],j];$
满足一段区间求极大极小值
所以就可以利用单调队列进行优化
为甚们是i-w-1 ? 而不是前面的数
因为我们定义的时候i-w-1 并不是一定要买 所以是前面的最优状态

至于初始值怎么赋?
除了f[0][0] 的状态都赋值为-inf
其余的每次取到能买的上限 具体看代码
code:

 

// 
#include<bits/stdc++.h> 
using namespace std; 
#define maxnn 3000 
#define ll long long  
ll T,P,w; 
ll f[maxnn][maxnn]; 
ll A1[maxnn],A2[maxnn],B1[maxnn],B2[maxnn]; 
deque<int > Q; 
int main() 
 
    cin>>T>>P>>w; 
    for(int i=1;i<=T;i++) 
        cin>>A1[i]>>B1[i]>>A2[i]>>B2[i]; 
     
    for(int i=0; i<=T; i++)for(int j=0; j<=P; j++)f[i][j]=-2333333;
    f[0][0]=0;
     for(int i=1; i<=T; i++) 
        Q.clear();
        for(int j=0; j<=A2[i]; j++)f[i][j]=-j*A1[i];
        for(int j=0; j<=P; j++)f[i][j]=max(f[i][j],f[i-1][j]);
        if(i-w-1<0)continue;
        Q.clear(); 
        Q.push_back(0); 
        int index=0; 
        for(ll j=0;j<=P;j++) 
             
            while(Q.size()&&Q.front()<j) 
             
                Q.pop_front(); 
             
            while(index<=min(P,B2[i]+j)) 
             
                while(Q.size()&&(f[i-w-1][Q.back()]+B1[i]*Q.back())<=(f[i-w-1][index]+B1[i]*index)) 
                 
                    Q.pop_back(); 
                 
                Q.push_back(index); 
                index++; 
             
            f[i][j]=max(f[i][j],f[i-w-1][Q.front()]+B1[i]*(Q.front())-j*B1[i]); 
         
        index=0; 
        Q.clear(); 
        Q.push_back(index); 
            for(ll j=0;j<=P;j++) 
         
            while(Q.size()&&Q.front()<j-A2[i]) 
             
                Q.pop_front(); 
             
            while(index<=min(P,j)) 
             
                while(Q.size()&&(f[i-w-1][Q.back()]+A1[i]*Q.back())<=(f[i-w-1][index]+A1[i]*index)) 
                 
                    Q.pop_back(); 
                 
                Q.push_back(index); 
                index++; 
             
            f[i][j]=max(f[i][j],f[i-w-1][Q.front()]+A1[i]*(Q.front())-j*A1[i]); 
         
     
    ll ans=-111110; 
    for(int i=0;i<=P;i++) 
     
        ans=max(ans,f[T][i]); 
     
    cout<<ans; 
 

以上是关于单调队列优化DP的主要内容,如果未能解决你的问题,请参考以下文章

单调队列优化DP

7.14 单调栈 单调队列 +dp优化

单调队列优化DP烽火传递 LibreOJ - 10180

bzoj 1855 dp + 单调队列优化

dp优化1——sgq(单调队列)

单调队列优化DP,多重背包