• 最大子序和 单调队列


    最大子序和

    Time Limit: 1 Sec Memory Limit: 256 MB

    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(1<=n,m<=300000) 第二行有n个数,要求在n个数找到最大子序和。

    Output

    一个数,即最大子序和S(S值不超过long long int)。

    Sample Input

    6 4

    1 -3 5 1 -2 3

    Sample Output

    7

    分析:

     若 k < i < j,且 s[k] > s[i],则 s[j] - s[i] > s[j] - s[k],即 a[i] +...+ a[j] > a[k] + ... + a[j]

    所以只需要枚举j,并找到每段区间中的最小值s[i]即可

    int n,m;
    cin>>n>>m;
    for(int i=1;i<=n;i++)scanf("%d",&a[i]),s[i] = s[i-1] + a[i];
    //s[i] = a[1] + ... + a[i]; 
    int l = 1,r = 1; // 维护队列左右边界 
    q[l] = 0;//q 单调队列 存下标 
    
    ans = -0xfffffff;// ans初始化为极小值
    for(int i=1;i<=n;i++)
    {
        while(l<=r && q[l]<i-m) l++;
        ans = max(ans,s[i] - s[q[l]]);
        while(l<=r && s[q[r]]>s[i]) r--;
        q[++r] = i;
    }
        
    printf("%lld",ans);

     WA原因:

    思路是长度为m的区间内的最大值减最小值,然后再判断一下最值的下标关系。实际上这样的贪心思路有可能出错。

    况且单减的数据会出问题。

    附WA代码

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #include<queue>
    #include<cstdlib>
    #include<cstring>
    #define sizen 300050
    using namespace std;
    struct node
    {
        int number,order;
    };
    long long int num[sizen]={0};
    int v[sizen];
    node maxx[sizen],minn[sizen];
    node q[sizen];
    int main()
    {
        //freopen("sum.in","r",stdin);
        //freopen("sum.out","w",stdout);
        
        int n,m,head = 0,tail = 0;
        long long int ans = 0;
        scanf("%d%d",&n,&m);
        for(int i=1;i<=n;i++)scanf("%d",&v[i]);
        
        for(int i=1;i<=n;i++)
        num[i] = num[i-1] + v[i];
         
        for(int i=0;i<=m;i++)
        {
            if(i == 0)q[tail].number = num[i],q[tail++].order = i;
            else
            {
                while(head != tail && q[tail-1].number < num[i])tail--;
                q[tail].number = num[i],q[tail++].order = i;
            }
            maxx[i].number = q[head].number,maxx[i].order = q[head].order;
        }
        
        for(int i=m+1;i<=n;i++)
        {
            while(head != tail && q[tail - 1].number < num[i])tail--;
            q[tail].number = num[i],q[tail++].order = i;
            if(q[head].number == num[i - m - 1])head++;
            maxx[i].number = q[head].number,maxx[i].order = q[head].order;
        }
        
        head = 0;
        tail = 0;
        for(int i=0;i<=m;i++)
        {
            if(i == 0)q[tail].number = num[i],q[tail++].order = i;
            else
            {
                while(head != tail && q[tail-1].number > num[i])tail--;
                q[tail].number = num[i],q[tail++].order = i;
            }
            minn[i].number = q[head].number,minn[i].order = q[head].order;
        }
        for(int i=m+1;i<=n;i++)
        {
            while(head != tail && q[tail - 1].number > num[i])tail--;
            q[tail].number = num[i],q[tail++].order = i;
            if(q[head].number == num[i - m - 1])head++;
            minn[i].number = q[head].number,minn[i].order = q[head].order;
        }
        
    
        for(int i=0;i<=n;i++)
        {
            if(maxx[i].order >= minn[i].order && maxx[i].number - minn[i].number > ans)
            ans = maxx[i].number - minn[i].number;
        }
        
        printf("%lld",ans);
        
        fclose(stdin);
        fclose(stdout);
        return 0;
    }
     
    View Code
  • 相关阅读:
    第三发
    第二发
    第一发
    要看的算法
    haxe坑
    TCP/IP协议三次握手与四次握手流程解析(转)
    Android动态类生成预加载-dexmaker使用
    Java中ArrayList 、LinkList区别
    Java解析YAML和Android解析YAML
    Java sax、dom、pull解析xml
  • 原文地址:https://www.cnblogs.com/Cindy-Chan/p/11213290.html
Copyright © 2020-2023  润新知