琪露诺 双端队列优化转移方程

众所周知,琪露诺是以笨蛋闻名的冰之妖精。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;
}
相关文章
相关标签/搜索