zoukankan      html  css  js  c++  java
  • 【CH1201】最大子序列和

    一道关于单调队列的模板题。

    题目要求求一段区间,使得这一段区间的和最大且区间长度不超过m。我们显然想到了先求出这个序列的前缀和sum,这样我们就能用O(1)的时间查询任意一个子序列的和。

    现在,我们枚举区间的右端点,对于每一个右端点i,我们要找到一个左端点j,使得sum[j]最小而且i-j≤m.

    因此,我们维护一个单调队列q。队列中存储左端点的下标,按照此下标所对应的sum值单调递增。当我们枚举到i时,我们检查队头的元素(最靠左的下标)是否满足题意(是否与i不超过m),将非法的下标出队,对于当前的i,j就是队头的元素。我们更新一次答案。之后,我们删除队尾,直到队尾对应的sum值小于sum[i],然后将i入队。

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <algorithm>
     5 using namespace std;
     6 typedef long long ll;
     7 int n,m,a[300010],sum[300010];
     8 inline int read() {
     9     int ret=0;
    10     int op=1;
    11     char c=getchar();
    12     while(c<'0'||c>'9') {if(c=='-') op=-1; c=getchar();}
    13     while(c<='9'&&c>='0') ret=ret*10+c-'0',c=getchar();
    14     return ret*op;
    15 }
    16 int ans,q[300010],l,r;
    17 int main() {
    18     n=read(); m=read();
    19     for(int i=1;i<=n;i++) {
    20         a[i]=read();
    21         sum[i]=sum[i-1]+a[i];
    22     }
    23     l=r=1;
    24     q[1]=0;
    25     for(int i=1;i<=n;i++) {
    26         while(l<=r&&i-m>q[l]) l++;
    27         ans=max(ans,sum[i]-sum[q[l]]);
    28         while(l<=r&&sum[i]<=sum[q[r]]) r--;
    29         q[++r]=i;
    30     }
    31     printf("%d
    ",ans);
    32     return 0;
    33 }
    AC Code
  • 相关阅读:
    golang单例模式
    PHP打开并修改文件
    关于文件服设计的一些想法
    Api
    golang Iterate through the fields of a struct in Go
    zookeeper note
    centos 6 install protoc
    todo
    linux route
    build http_load
  • 原文地址:https://www.cnblogs.com/shl-blog/p/10884716.html
Copyright © 2011-2022 走看看