花火は楽しい(単調キュー最適化DP)で鑑賞CF372Cを[簡単に読み取るために]

効果の対象に

そこストリート\(N \)地域。左から右に番号が付け\(1 \)\(\ N-) 隣接領域との間の距離である(1 \)\します
祭りの期間中、そこに(m個\)\花火をオフに設定する回。最初の\(私は\)回花火領域\(a_iを\) 幸福の属性\(b_i \) 時間がある\(T_I \) \(T_I \ leqslant T_ {I + 1} \)

あなたが最初にある場合、\(私は\)花火で起動したときに(X \ leqslant N)\ X (1 \ leqslant)\ で、あなたは価値幸せになります\( - | a_iを- X- | b_i \) (、注意してください幸福値)が負でもよいです。

あなたは、単位時間間隔内まで移動することができます\(dは\)ユニットが、メインストリートのうち禁止。また、あなたは(時間の初期モーメントが等しいにすることができます(1 \)\任意の領域に時間を)、および最大花火を見てから、幸福の合計を取得するために願っています。

幸せの和の最大出力。

答えの対象

この最適化問題は単調キューです\(DP \)の古典的な問題を。

\(dp[i][j]\)表示第\(i\)次烟花燃放时你位于\(j\)处所能获得的最大的幸福总和。

而第\(i-1\)次烟花燃放到第\(i\)次烟花燃放所能移动的最大距离为\(h=(t_i-t_{i-1})*d\)

所以该次燃放后可能获得的幸福总和由上一次位于\([j-h,j+h]\)处的\(2h+1\)种情形得到。

\(dp[i][j]=\max\{dp[i-1][k]+b[i]-|a[i]-j|\} \quad k\in [j-h,j+h]\)

\(dp[i][j]=\max\{dp[i-1][k]\}+b[i]-|a[i]-j| \quad k\in [j-h,j+h]\)

故对于\(j\in[1,n]\) ,要求\(dp[i][j]\)的值只要求解\(dp[i-1]\)数组位于\([j-h,j+h]\)的最大值,而求解这一步可以用单调队列解决,复杂度\(O(n)\),即可求解完\(dp[i]\)数组。

又发现\(dp[i]\)数组的求解只与\(dp[i-1]\)数组有关,故这一维可以滚动处理。

\(dp[s1]\)表示源状态,\(dp[s2]\)表示将求解状态,求解完交换\(s1\)\(s2\)即可。\(s1,s2\in\{0,1\}\)

单调队列处理部分

我的代码采用双端队列\(deque\)处理,较为简洁。

\(deque\)存储位置编号

其中\(deque\)中从队首到队尾,位置编号严格增加,该位置源状态\(dp\)源状态值严格减少;

处理位置\(i\)(采用代码中变量意义)时,将还未处理的小于\(i+h\)的位置依次入队尾(可能有些元素会被赶出队尾,因为它们不可能再被使用到),再将小于\(i-h\)的位置依次出队头。则队首所在位置便是源状态位于\([i-h,i+h]\)的最大值,即可得到现状态。

源代码

#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int maxn=15e4+10;
LL q,m,d,n,s1=0,s2=1;
LL dp[2][maxn];
int main(){
    scanf("%lld%lld%lld%",&n,&m,&d); 
    LL a,b,t,qian_t=1;
    while(m--){
        scanf("%lld%lld%lld%",&a,&b,&t);
        LL h=(t-qian_t)*d;
        qian_t=t;
        deque<int> qu;
        for(int i=1,j=1;i<=n;i++){
            for(;j<=i+h&&j<=n;j++){
                while(!qu.empty()&&dp[s1][qu.back()]<=dp[s1][j])qu.pop_back();
                qu.push_back(j);
            }
            while(!qu.empty()&&qu.front()<i-h)qu.pop_front();
            dp[s2][i]=dp[s1][qu.front()]+b-abs(i-a);
        }
        swap(s1,s2);
    }
    LL maxm=dp[s1][1];
    for(int i=2;i<=n;i++){
        if(dp[s1][i]>maxm)maxm=dp[s1][i];
    }
    printf("%lld",maxm);
}

结束语

欢迎留言!你们的支持与推荐是博主发展的动力XD.

おすすめ

転載: www.cnblogs.com/yehs/p/11331813.html