1. 程式人生 > >琪露諾

琪露諾

amp algo [1] string for cstring line ios pri

傳送門啦

本人第一個單調隊列優化 $ dp $,不鼓勵鼓勵?

琪露諾這個題,$ dp $ 還是挺好想的對不,但是暴力 $ dp $ 的話會 $ TLE $ ,所以我們考慮用單調隊列優化。

原題中說她只移動到區間 $ [i+L,i+R] $ 中的任意一格,所以我們單調隊列在轉移的時候 $ push $ 的應該是 $ dp[i-L] $ ,而不是 $ dp[i] $ ,對於每一段區間,我們用起點(隊頭)來更新答案就好了。

最後一步,因為區間的限制,我們只用在 $ [n-R+1,n] $ 中找一個最大值就好了。

#include <iostream>
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
const int maxn = 2 * 1e6;

inline int read(){
    char ch = getchar();
    int f = 1 , x = 0;
    while(ch > ‘9‘ || ch < ‘0‘){if(ch == ‘-‘)f = -1; ch = getchar();}
    while(ch >= ‘0‘ && ch <= ‘9‘){x = (x << 1) + (x << 3) + ch - ‘0‘;ch = getchar();}
    return x * f;
}

int n,L,R,a[maxn];
int f[maxn],q[maxn],head,tail;

int main(){
    n = read(); L = read(); R = read();
    for(int i=0;i<=n;i++){
        a[i] = read();
    }
    if(L > R) swap(L , R);
    head = tail = 1; q[1] = 0;
    for(int i=L;i<=n;i++){
        while(head <= tail && i - q[head] > R)
            head++;
        while(head <= tail && f[q[tail]] <= f[i-L])
            tail--;
        q[++tail] = i - L;
        f[i] = f[q[head]] + a[i];
    }
    int ans = 0;
    for(int i=n-R+1;i<=n;i++)
        ans = max(ans , f[i]);
    printf("%d\n",ans);
    return 0;
}

琪露諾