1. 程式人生 > >P1725 琪露諾 題解(單調佇列)

P1725 琪露諾 題解(單調佇列)

題目連結

琪露諾

解題思路

單調佇列優化的\(dp\)
狀態轉移方程:\(f[i]=max{f[i-l],f[i-l+1],...,f[i-r-1],f[i-r]}+a[i]\)
考慮單調佇列優化。
因為剛學,不是很熟悉單調佇列,特寫一篇詳細的解釋。
\(queue\) 陣列儲存一個佇列,他的頭部和尾部的下標分別用head和tail表示。
\(f\) 陣列是\(dp\)用到的陣列。
首先讀入每一個座標處的價值\(a[i]\)
列舉\(i\),從\(l\)\(n\),分別計算\(f[i]\),當\(i+r>n\)時,儲存最大值ans。
單調佇列的註釋寫在程式碼中。

AC程式碼

#include<stdio.h>
int i,n,l,r,a[200010],f[200010],ans=-2147483648;//這個題資料比較水,ans=0也能過,但理論上是不允許這樣的
int queue[200010],head=0,tail=-1;
int main(){
    scanf("%d%d%d",&n,&l,&r);
    for(i=0;i<n;i++){
        scanf("%d",&a[i]);
    }
    for(i=l;i<=n;i++){
        while(head<=tail&&queue[head]+r<=i)head++;//如果頭太靠前了,那就刪掉
        while(head<=tail&&f[queue[tail]]<=f[i-l])tail--;//如果尾巴對應的a太小了,那就刪掉
         //這兩句保證了單調佇列的不上升也即單調減特性,保證頭永遠是當前狀態的最佳狀態
        queue[++tail]=i-l;//儲存上一次是從哪裡來的
        f[i]=a[i]+f[queue[head]];//從上一步跳過來,跳到這裡的最大值
        if(i>n-r&&f[i]>ans)ans=f[i];
    }
    printf("%d",ans);
    return 0;
}