zoukankan      html  css  js  c++  java
  • 《算法竞赛进阶指南》0x12 单调队列 不超过M长度的最大子段和

    题目链接:https://www.acwing.com/problem/content/description/137/

    首先考虑朴素算法,对于一个端点i,考虑前面的[i-m,i-1]的前缀和,sum[i]-minsum[j] 1<=i<=n,可以维护一个长度为M的队列,对于下一个i,搜索队列中的最小值,将i插入,将前面超出长度M的部分移除。

    但是这样的话时间复杂度很高。对于正在维护的队列,考虑到对于k<j<i,如果有sum[k]>=sum[j],那么k永远不会比j更优,所以队列中只需要维护单调的数即可。这就是单点队列的应用。

    时间复杂度是O(n)

    代码:

    #include<bits/stdc++.h>
    using namespace std;
    #define maxn 3000010
    int n,m;
    int sum[maxn],q[maxn];
    int main(){
        int l=1,r=1;
        cin>>n>>m;
        for(int i=1;i<=n;i++)
        {
            int x;
            scanf("%d",&x);
            sum[i]=sum[i-1]+x;
        }
        q[1]=0;//队列中存放的是所有的决策位置,初始时,长度不满M,从[1,i]决策 
        int ans=-0x7f7f7f7f;
        for(int i=1;i<=n;i++){
            while(l<=r && q[l]<i-m)l++;
            ans=max(ans,sum[i]-sum[q[l]]);
            while(l<=r && sum[q[r]]>=sum[i])r--;//保持队列的单调性
            q[++r]=i; 
        }
        cout<<ans<<endl;
    }
  • 相关阅读:
    无题
    2G日产金士顿
    提防假TF卡,金士顿的识别 (有图)
    无题
    推荐小说
    开学了!
    测速软件
    提供《鬼吹灯》小说系列下载
    换博客了
    Kali_2020.01安装教程
  • 原文地址:https://www.cnblogs.com/randy-lo/p/13151954.html
Copyright © 2011-2022 走看看