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

    Description

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

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

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

    Input

    第一行两个数n,m
    第二行有n个数,要求在n个数找到最大子序和

    Output

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

    Sample Input

    6 4

    1 -3 5 1 -2 3

    Sample Output

    7

    Hint

    数据范围:
    100%满足n,m<=300000
     
    /*
        区间和→两个前缀和相减
        求出s[i]表示序列前i项的和,则区间[i,j]中数的和=s[j]-s[i-1]。
        问题变为找出两个位置i,j,使得s[j]-s[i]最大并且j-i<=m。
        枚举右端点i,若i固定,问题变为找到j∈[i-m,i-1]使得s[j]最小
        若k<j<i,并且s[k]>=s[j],则在i及i之后的扫描中,k永远不会成为最优决策。
        可以维护一个下标位置递增、对应前缀和的值递增的队列,当i变化时及时判断队头是否超出m的范围,取队头为最优解,然后在队尾插入新的i并维护单调性,时间复杂度O(N)。
    */
    
    #include<iostream>
    #include<cstdio>
    using namespace std;
    int a[300010];
    struct node
    {
        int sum,xb;
    }q[300010];
    int head=1,tail=0,ans=0;
    int main()
    {
        int n,m;
        cin>>n>>m;
        for (int i=1;i<=n;i++) cin>>a[i];
        for (int i=1;i<=n;i++) a[i]=a[i]+a[i-1];
        q[++tail].sum=a[1];q[tail].xb=1;ans=a[1];//从2开始循环,所以ans初值赋为a[1] 
        for (int i=2;i<=n;i++)
        {
            while (q[tail].sum>=a[i] && tail>=head) tail--;//维护单调性 
            q[++tail].xb=i; q[tail].sum=a[i];
            if (i-m>q[head].xb) head++;
            ans=max(ans,a[i]-q[head].sum);
        }
        cout<<ans;
    }
  • 相关阅读:
    字符统计和滑动窗口
    字典树应用及用哈希表代替
    迷宫里的动态规划应用
    求所有排列中的第 i 个排列的问题
    最大子串和问题
    二分查找、变形及应用
    前 n 个数原址排序的问题
    LeetCode 32 括号匹配
    11.常用的API
    10.正则表达式
  • 原文地址:https://www.cnblogs.com/liumengyue/p/5189117.html
Copyright © 2011-2022 走看看