• icpc 南昌邀请赛网络赛 Max answer


    就是求区间和与区间最小值的积的最大值 但是a[i]可能是负的 这就很坑 赛后看了好多dalao的博客 终于a了

    这个问题我感觉可以分为两个步骤

    第一步是对于每个元素 以它为最小值的最大区间是什么

    第二步是找出来在这个区间里面 最大的连续和多少

    那么我们怎么找到第一步这个最大区间呢

    可以先找这个元素左边第一个比他小的值的下标 和右边第一个比他小的值的下标 这两个下标确定了 最大区间就确定了

    怎么找这个下标呢 暴力的话时间复杂度太高 是n^2 需要使用单调栈:

    单调栈 顾名思义就是元素都是单调递增或者递减的栈 至于它有什么作用 接着往下看

    假如有一个数组a:   3 5 1 6 2

    用数组 L 表示a数组里的每一个元素 从自身位置 向左 第一个比它小的元素的位置

    那么L就应该是: 0 1 0 3 3 (这里为了方便表示 我让a数组的下标从1开始标记 这样L数组里面 0 就表示左边的数都比他大 1 就表示第一个数比他小 以此类推)

    那么我们怎么利用单调栈实现呢?

    先将 a[0]赋值为一个极小值 -0x7ffffff,然后将0入栈

    对于数组a的每一个元素 进行如下语句:

    while(a[S.top()]>=a[i]) 
            S.pop();      
    l[i] = S.top();
    S.push(i);

    while语句 保证了栈里面的数据是单调递减的

    看不明白没有关系 让我们模拟一下:
    i==1时 a[S.top]=a[0]=-0x7ffffff 不进入while循环

    所以L[1]=0;

    将1入栈 此时的栈:0 1(实际上我们比较的是a[i] 所以逻辑上来讲 此时的栈:a[0] a[1] 也就是 -0x7ffff 3 因为我们需要用到左边的下标值 所以是将下标入栈 这样既可以访问到下标所对应的值 也可以访问下标)

    i==2时,a[S.top]=a[1]=3 小于5 还是不进入while循环

    L[2]=S.top()=1

    将2入栈 此时的栈:0 1 2(-0x7ffff  3  5 )

    i==3时,a[S.top]=a[2]=5 大于1

    S.pop(),a[S.top]=a[1]=3还是大于1

    S.pop(),a[S.top]=a[0]=-0x7ffffff 小于1 结束循环

    所以L[3]=0

    将3入栈 此时的栈:0 3(-0x7ffff  1)

    .........

    以此类推

    逻辑上栈中的元素(a[i])始终是递减的

    这样我们就通过以此循环求出了L数组 也就是找到了之前说的 最大区间的左边界 找右边界也是一样的思路,只是循环的方向不同

    好了现在我们完成了第一步 要进行第二步 也就是找每个区间里面的最大连续和(如果a[i]<0的话需要找最小连续和)

    如果a[i]均为非负的话就很简单了 肯定是区间越长 连续和越大 但问题是a[i]是可以有负数的

    那就需要分情况讨论了

    我们可以开4个数组 lmax lmin rmax rmin

    lmax 和 rmax 用来记录最大连续和的区间的左右下标

    lmin 和 rmin 记录最小的和的左右下标

    怎么更新这四个数组呢?

    for(i=2;i<=n;i++)
        {
            if(s[i-1]-s[lmin[i-1]-1]>0)
            lmin[i]=i;
            else
            lmin[i]=lmin[i-1];
            if(s[i-1]-s[lmax[i-1]-1]<0)
            lmax[i]=i;
            else
            lmax[i]=lmax[i-1];
        }

    s[i]是前i项的和

    看代码很容易理解 如果前面几项的和是正的 那就不要他 让lmin[i]=i 如果是负的 那么加上他 这样连续和就会变小

    rmax和rmin只需要倒着更新就行

    最后别忘了 这四个数组必须是在L数组和R数组的范围内的 相当于第一步是第二步的限制条件:

        if(a[i]<0)
            {
                ll=max(l[i]+1,lmin[i]);
                rr=min(r[i]-1,rmin[i]);
            }
            else
            {
                ll=max(l[i]+1,lmax[i]);
                rr=min(r[i]-1,rmax[i]);
            }

    完整ac代码:

    #include<bits/stdc++.h>
    
    using namespace std;
    
    long long i,n,ll,rr,s[500005],a[500005],lmin[500005],lmax[500005],rmin[500005],rmax[500005],l[500005],r[500005],ans;
    stack<long long> S;
    
    int main()
    {
        cin>>n;
        for(i=1;i<=n;i++)
        {
            cin>>a[i];
            s[i]=s[i-1]+a[i];
        }
        ans=a[1]*a[1];
        S.push(0);
        a[0]=-0x7fffff;
        a[n+1]=-0x7fffff-1;
        for(i=1;i<=n;i++)
        {
            while(a[S.top()]>=a[i]) 
                S.pop();      
                l[i] = S.top();
            S.push(i);
        }
        while(S.size())
        S.pop();
        S.push(n+1);
        for(i=n;i>=1;i--)
        {
            while(a[S.top()]>=a[i])
                S.pop();
                r[i]=S.top();
            S.push(i);
        }
        lmin[1]=1;
        lmax[1]=1;
        rmin[n]=n;
        rmax[n]=n;
        for(i=2;i<=n;i++)
        {
            if(s[i-1]-s[lmin[i-1]-1]>0)
            lmin[i]=i;
            else
            lmin[i]=lmin[i-1];
            if(s[i-1]-s[lmax[i-1]-1]<0)
            lmax[i]=i;
            else
            lmax[i]=lmax[i-1];
        }
        for(i=n-1;i>=1;i--)
        {
            if(s[rmin[i+1]]-s[i]>0)
            rmin[i]=i;
            else
            rmin[i]=rmin[i+1];
            if(s[rmax[i+1]]-s[i]<0)
            rmax[i]=i;
            else
            rmax[i]=rmax[i+1];
        }
        for(i=1;i<=n;i++)
        {
            if(a[i]<0)
            {
                ll=max(l[i]+1,lmin[i]);
                rr=min(r[i]-1,rmin[i]);
            }
            else
            {
                ll=max(l[i]+1,lmax[i]);
                rr=min(r[i]-1,rmax[i]);
            }
            ans=max(ans,a[i]*(s[rr]-s[ll-1]));
        }
        cout<<ans;
        
     } 
  • 相关阅读:
    hadoop用到的shell脚本
    hadoop搭建完全分布式集群
    hadoop搭建伪分布式集群
    ARM Compute Library编译安装
    OpenBlas交叉编译安装
    正则表达式去除所有标签html标签
    xstream实现xml字符串与对象直接的转换
    spring-boot中使用mybatis-plus代码生成器让你轻松的完成单表的CURD
    开源、免费软件和网站分享
    2020春软件工程助教工作期末总结
  • 原文地址:https://www.cnblogs.com/dyhaohaoxuexi/p/10757005.html
Copyright © 2020-2023  润新知