琪露諾 雙端隊列優化轉移方程

衆所周知,琪露諾是以笨蛋聞名的冰之妖精。node

題目:https://www.luogu.org/problemnew/show/P1725優化

 

顯然,是一道DP題(很噁心顯然二字,如今來噁心大家)spa

 

狀態轉移是dp[i]=max(dp[k])+a[i];code

跳到當前位置的最大值是前面能跳到到這裏的全部位置的最大值加上當前位置的冰凍值;blog

爲何要用雙端隊列呢(由於爽啊)隊列

這個很裸了已經,滑動窗口的思想。就是純DP是會T的,因此咱們尋找最大值時要優化時間;get

若是當前的值比隊列中的值大,就把隊列中的已有元素彈出(由於咱們是從前日後遍歷的,一個位置在前且值小的元素是不會作出任何貢獻的);string

代碼it

#include<cstdio>
#include<cstring>
#include<deque>
#include<algorithm>
using namespace std;
const int maxn=200100;
struct node
{
    int val;//DP最大值 
    int num;//
};

int n,a[maxn],l,r;
int dp[maxn];
deque <node> s;
int main()
{
    scanf("%d%d%d",&n,&l,&r);
    for(int i=0;i<=n;i++)
    {
        scanf("%d",a+i);
    }
    int tail=0;dp[tail]=0;
    node x;
    for(int i=l;i<=n;i++)//從0開始轉移向l處 
    {
        while(s.size()&&dp[tail]>=s.back().val)
        {
            s.pop_back();
        }//無用值彈出 
        x.num=tail;x.val=dp[tail];
        s.push_back(x);//加入新值 
        if(tail-s.front().num>=(r-l+1)) s.pop_front();//隊列的長度 
        dp[i]=s.front().val+a[i];//此時隊列最前面的是前面能到達i的最大值 
        tail++;
    }
    int ans=-maxn;
    for(int i=n-r+1;i<=n;i++)
    {
        ans=max(ans,dp[i]);
    }
    printf("%d",ans);
    return 0;
}
相關文章
相關標籤/搜索