zoukankan      html  css  js  c++  java
  • 琪露诺 双端队列优化转移方程

    众所周知,琪露诺是以笨蛋闻名的冰之妖精。

    题目:https://www.luogu.org/problemnew/show/P1725

    显然,是一道DP题(很恶心显然二字,现在来恶心你们)

    状态转移是dp[i]=max(dp[k])+a[i];

    跳到当前位置的最大值是前面能跳到到这里的所有位置的最大值加上当前位置的冰冻值;

    为什么要用双端队列呢(因为爽啊)

    这个很裸了已经,滑动窗口的思想。就是纯DP是会T的,所以我们寻找最大值时要优化时间;

    如果当前的值比队列中的值大,就把队列中的已有元素弹出(因为我们是从前往后遍历的,一个位置在前且值小的元素是不会做出任何贡献的);

    代码

    #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;
    }
  • 相关阅读:
    数论知识点--以及模板
    【数学+思维】ZZULIOJ 1531: 小L的区间求和
    记忆化搜索模板题---leetcode 1155. 掷骰子的N种方法
    拓扑排序
    ZOJ
    multiset的应用
    HDU
    HDU
    D. Beautiful Array
    HDU
  • 原文地址:https://www.cnblogs.com/WHFF521/p/10960285.html
Copyright © 2011-2022 走看看