• CH 1201


    题目链接:传送门

    描述
    输入一个长度为n的整数序列,从中找出一段不超过m的连续子序列,使得整个序列的和最大。

    例如 $1,-3,5,1,-2,3$。

    当 $m=4$ 时,$S=5+1-2+3=7$;
    当 $m=2$ 或 $m=3$ 时,$S=5+1=6$。

    输入格式
    第一行两个数 $n,m(n,m le 300000)$
    第二行有 $n$ 个数,要求在 $n$ 个数找到最大子序和

    输出格式
    一个数,数出他们的最大子序和

    样例输入
    6 4
    1 -3 5 1 -2 3
    样例输出
    7

    题解:

    设这 $n$ 个数的前缀和为 $s_1 sim s_n$。考虑枚举右端点 $i$,当右端点 $i$ 固定时,显然连续子序列的和为 $s_i - s_{j-1}$。

    因此相当于我们要寻找一个点 $y$,使其满足 $y in [i-m, i-1]$ 的前提下 $s_y$ 最小。

    显然,当对于满足 $i-m le x < y < i$ 的两个点 $x,y$,如果 $s_x ge s_y$,显然 $x$ 点不能成为最优解,因此可以直接舍弃掉 $x$。

    因此,用一个双端队列维护 $j$,队列中的 $j$ 满足随着下标的递增,相应的 $s_j$ 也是递增的。

    这样一来,每次对于 $i$ 寻找 $j$,只要从头部抛去 $s_$ 点,剩下来的队头就是最优的 $j$。 

    而当前 $i$ 入队,为了保持队列的递增性,因此要在队尾抛去所有 $s_{back} ge s_i$ 的点。

    时间复杂度:所有点出入队一次,$O(n)$。

    AC代码:

    #include<bits/stdc++.h>
    using namespace std;
    const int INF=0x3f3f3f3f;
    const int maxn=300000+10;
    int n,m,ans;
    int a[maxn],s[maxn];
    deque<int> Q;
    int main()
    {
        std::ios::sync_with_stdio(false);
        cin>>n>>m;
        ans=-INF, s[0]=0;
        Q.push_back(0);
        for(int i=1;i<=n;i++)
        {
            cin>>a[i], s[i]=s[i-1]+a[i];
            while(!Q.empty() && Q.front()<i-m) Q.pop_front();
            ans=max(ans,s[i]-s[Q.front()]);
            while(!Q.empty() && s[Q.back()]>=s[i]) Q.pop_back();
            Q.push_back(i);
        }
        cout<<ans<<endl;
    }
  • 相关阅读:
    js中this指向的三种情况
    js 对象克隆方法总结(不改变原对象)
    JS 数组克隆方法总结(不可更改原数组)
    第七章、函数的基础之函数体系01
    第六篇、文件处理之文件修改的两种方式
    第六篇、文件处理之文件的高级应用
    第六篇.文件处理之python2和3字符编码的区别
    第六篇、文件处理之字符编码
    第五篇python进阶之深浅拷贝
    jquery的insertBefore(),insertAfter(),after(),before()
  • 原文地址:https://www.cnblogs.com/dilthey/p/9929329.html
Copyright © 2020-2023  润新知