• 最大子序和 (单调队列)


    https://www.acwing.com/problem/content/137/

    我们知道不加长度限制的最大子序列和可以用贪心轻松解决。然而这道题中给子序列增加了一个最大长度为m的限制,那么贪心就不正确了。

    首先将区间和转化为前缀和之差,那么[l,r]的区间和应该是S[r]-S[l-1]。那么该问题就转化为找到x,y(x<y且y-x<=m)使得S[y]-S[x]最大。

    如果y固定,那么S[x]自然是越小越好,那么如果我们能维护一个单调递增的队列,这个问题就可以解决了。

    使用单调队列,依次push编号入队,在每个编号i即将入队时进行一下决策:

    1.如果i-队首编号>m,则弹出队首元素。

    2.经过1步骤之后,队首元素就是对于i的最优左端点。若队列为空,则i的左端点就是自身。

    3.循环弹出S值大于S[i]的队尾元素。

    4.将i压入队尾。

    #include <iostream>
    #include <stdio.h>
    #include <stdlib.h>
    #include <deque>
    using namespace std;
    typedef long long LL;
    deque<LL> dq;
    int n,m;
    LL sum[300010];
    
    
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++) scanf("%lld",&sum[i]);
        for(int i=1;i<=n;i++) sum[i]=sum[i]+sum[i-1];
        LL ans=-1e18;
        dq.push_back(0);
        for(int i=1;i<=n;i++)
        {
            while(!dq.empty()&&dq.front()<i-m) dq.pop_front();
            if(dq.empty()) ans=max(ans,sum[i]);
            else ans=max(ans,sum[i]-sum[dq.front()]);
            while(!dq.empty()&&sum[dq.back()]>=sum[i]) dq.pop_back();
            dq.push_back(i);
        }
        printf("%lld
    ",ans);
        return 0;
    }
  • 相关阅读:
    java文件配置MySQL
    logback.xml
    Apache Commons之commons-lang
    Codec入门
    Mysql命令增加、修改、删除表字段
    markDown的简单使用
    Vert.x核心包各功能模块详解
    StringJoiner使用详解
    Vert.x初体验
    Docker镜像备份与迁移
  • 原文地址:https://www.cnblogs.com/BakaCirno/p/11297340.html
Copyright © 2020-2023  润新知