zoukankan      html  css  js  c++  java
  • 51nod 1254 最大子段和 V2 ——单调栈

    N个整数组成的序列a[1],a[2],a[3],…,a[n],你可以对数组中的一对元素进行交换,并且交换后求a[1]至a[n]的最大子段和,所能得到的结果是所有交换中最大的。当所给的整数均为负数时和为0。
    例如:{-2,11,-4,13,-5,-2, 4}将 -4 和 4 交换,{-2,11,4,13,-5,-2, -4},最大子段和为11 + 4 + 13 = 28。
     
    Input
    第1行:整数序列的长度N(2 <= N <= 50000)
    第2 - N + 1行:N个整数(-10^9 <= A[i] <= 10^9)
    Output
    输出交换一次后的最大子段和。
    Input示例
    7
    -2
    11
    -4
    13
    -5
    -2
    4
    Output示例
    28
    ——————————————————————————————
    这道题可以做到O(n) 但是瓶颈在读入

    ——————————————————————————————

    这道题 我们可以枚举右端点
    这个我们先强制我们换的数只能是右端点后面的数(之后把数组倒过来再来一次就可以了)
    维护一波后缀和(s【i】表示i-n的和)以及后缀最大值 (mx【i】表示i-n的mx
    那么我们枚举右端点之后 目的自然是求 到i的后缀和s【l】 减去 l到i的区间的最小值(min【l,r】) 的最优解
    答案就是s【l】-min【l,r】-s【i+1】+mx【i+1】
    那么因为 -s【i+1】+mx【i+1】已知
    我们要维护的就是s【l】-mn【l,r】
    我们可以利用单调栈维护每个mn所能占领的区间
    这样就把数列分成了若干个区间 然后维护区间max(s【l】)
    根据每个区间的情况记录最优解 很明显最优解只会越来越优
    这样我们每次移动右端点的时候 就用当前端点的值v【i】去弹出栈的元素
    然后更新新的区间的信息就好了
    #include<stdio.h>
    #include<cstring>
    #include<algorithm>
    #define LL long long
    using namespace std;
    const int M=55007;
    const LL inf=1e15;
    char buf[11*M],*ptr=buf-1;
    int read(){
        int ans=0,f=1,c=*++ptr;
        while(c<'0'||c>'9'){if(c=='-') f=-1; c=*++ptr;}
        while(c>='0'&&c<='9'){ans=ans*10+(c-'0'); c=*++ptr;}
        return ans*f;
    }
    int n;
    LL c[M],v[M],s[M],mx[M],mxh,ans;
    int cnt;
    struct node{LL mn,h;}q[M];
    void solve(){
        mxh=-inf; cnt=0;
        for(int i=n;i;i--) s[i]=s[i+1]+v[i],mx[i]=max(mx[i+1],v[i]);
        for(int i=1;i<=n;i++){
            LL nowh=s[i];
            while(cnt&&q[cnt].mn>=v[i]) nowh=max(nowh,q[cnt].h),cnt--;
            q[++cnt].mn=v[i]; q[cnt].h=nowh; 
            mxh=max(mxh,nowh-v[i]);    ans=max(ans,mxh-s[i+1]+mx[i+1]);
        }
    }
    int main(){
        fread(buf,1,sizeof(buf),stdin);
        n=read();
        for(int i=1;i<=n;i++) v[i]=read(); v[n+1]=-inf;
        for(int i=n;i;i--) s[i]=s[i+1]+v[i],mx[i]=max(mx[i+1],v[i]);
        solve();
        reverse(v+1,v+1+n);
        solve();
        printf("%lld
    ",ans);
        return 0;
    }
    View Code
     
  • 相关阅读:
    Android实战经验之图像处理及特效处理的集锦(总结版)
    Android类似于滚动的通知栏实现
    Python概览
    高效程序员的45个习惯读书笔记
    Web前台传对象字符串到后台并让后台反序列化对象字符串的方法(ASP.NET)
    发布订阅者模式之C#委托实现
    表数据复制(迁移)
    Code Smell
    Python学习过程遇到的Bug不断更新
    Resharper 7小技巧系列:导航、书签、和最近编辑
  • 原文地址:https://www.cnblogs.com/lyzuikeai/p/7445364.html
Copyright © 2011-2022 走看看