Luogu P1725 琪露諾

題目

Luogu P1725 琪露諾

分析

看上去像一道DP題。用dp[i]表示到達座標i時的最大冰凍指數,可以得到轉移方程:

dp[i]=max{dp[k]}+a[i],k∈[i-l,i-r]

題目中提到,只要她下一步的位置編號大於N就算到達對岸,因此枚舉i時要[l,n+r),因爲[0,l]的部分她不可能到達,但[n,n+r)的部分都有可能是到對岸之前的那一步,走到對岸時到達的座標。能夠轉移到當前座標i的範圍是[i-l,i-r](可以反推幫助理解),所以k∈[i-l,i-r]。總複雜度O(N^2),顯然爆炸。
於是考慮優化,靜心觀察可以發現,[i-l,i-r]中只有最大的a[k]纔會作爲轉移向下一步的狀態,因爲各個子區間是以一個單位座標向對岸移動的,所以在每一個子區間中取較小的a[k]向之後的座標轉移不如選擇最大的a[k]要優。換言之,這種貪心是正確的,因爲一個座標會被多個區間覆蓋,所以不許考慮通常題目中捨棄當前最有以求得下一步更優,來達到全局最優的目的。
那麼這顯然具有單調性!維護一個單調遞增的隊列,存放每一個[i-l,i-r]中最優的a[k]的座標。由於每個座標或進隊或出隊,因此相當於進行了O(N)的訪問,總複雜度即爲O(N)。

代碼

#include<cstdio>
#include<iostream>
using namespace std;
const int maxn=200002;
int a[maxn*2],dp[maxn*2],q[maxn*10];
int main()
{
    int n,l,r;
    scanf("%d%d%d",&n,&l,&r);
    for(int i=0;i<=n;i++)
        scanf("%d",&a[i]);
    int head=1,tail=1;
    for(int i=l;i<n+r;i++)
    {
        while(head<=tail&&dp[i-l]>=dp[q[tail]]) 
            tail--;
        q[++tail]=i-l;
        while(head<=tail&&q[head]<i-r)
            head++;
        dp[i]=dp[q[head]]+a[i];
    }
    int ans=-2147483647;
    for(int i=n+1;i<=n+r;i++)   
        ans=max(ans,dp[i]);
    printf("%d",ans);
    return 0; 
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章