zoukankan      html  css  js  c++  java
  • 洛谷 P1121 环状最大两段子段和 题解

    题面

    我来一发很实用的题解;

    本人想出了O(n)的做法,是一种DP;

    先说大体思路:

    答案分两种情况,一种是选择的两段均不跨越n到1(也就是环),另一种是选择的两段跨过了环;

    如果均不跨越环,那么也就是意味着这是一道模板题;

    设maxl[i]表示从1~i的最大字串和,maxr[i]表示i~n的最大字段和;
    很明显的:答案就是max(maxl[i]+maxr[i+1])
    ```cpp
    maxl[i]=max(a[i],maxl[i-1]+a[i]);//表示这一位是不是一段区间的开头;
    maxl[i]=max(maxl[i-1],maxl[i]);
    maxr[i]=max(a[i],maxr[i+1]+a[i]);
    maxr[i]=max(maxr[i],maxr[i+1]);
    ```
    所以目前你的期望分数就是50了;


    然后处理环:

    我们换种思维,就好比并查集维护联通时可以运用逆向思维一样,把拆边改为加边,你求1~n带环的最大值就等价于求(1~n的区间和)减去(1~n的两段区间最小值)

    求最小值的方法和求最大值的方法是一样的,稍加更改就可以了;

    然后期望分数100

    然后就A了吗?

    嗯~?怎么才打了80分?

    你跑一遍程序,试试这组数据:
    3
    -2 -4 -5

    你的多少?0?正解是-6啊!

    这是因为题中要求是两段非空的字串,所以当整个串都是负数时应该特判,选择最大的两个值加起来就是答案了;

    #include <bits/stdc++.h>
    #define int long long
    using namespace std;
    long long a[200010];
    long long maxl[200010],minl[200010],maxr[200010],minr[200010];
    signed main()
    {
        int n;
        cin>>n;
        long long sum=0;
        long long maxn=-999999999999;
        for(register int i=1;i<=n;i++){
            cin>>a[i];
            maxn=max(maxn,a[i]);
            sum+=a[i];
        }
        for(register int i=1;i<=n;i++){
            maxl[i]=maxr[i]=-999999999999;
            minl[i]=minr[i]=999999999999;
        }
        maxl[1]=a[1];
        minl[1]=a[1];
        maxr[n]=a[n];
        minr[n]=a[n];
        for(register int i=2;i<=n;i++){
            maxl[i]=max(a[i],maxl[i-1]+a[i]);
            minl[i]=min(a[i],minl[i-1]+a[i]);    
        }    
        for(register int i=2;i<=n;i++){
            maxl[i]=max(maxl[i-1],maxl[i]);
            minl[i]=min(minl[i-1],minl[i]);
        }
        for(register int i=n-1;i>=1;i--){
            maxr[i]=max(a[i],maxr[i+1]+a[i]);
            minr[i]=min(a[i],minr[i+1]+a[i]);        
        }
        for(register int i=n-1;i>=1;i--){
            maxr[i]=max(maxr[i],maxr[i+1]);
            minr[i]=min(minr[i],minr[i+1]);
        }
        long long anspart1=-999999999999,anspart2=999999999999;
        for(register int i=1;i<=n;i++){
            anspart1=max(anspart1,maxl[i]+maxr[i+1]);
            anspart2=min(anspart2,minl[i]+minr[i+1]);
        }
        long long ans=max(anspart1,sum-anspart2);
        sort(a+1,a+1+n);
        if(sum==anspart2){
            ans=a[n]+a[n-1];
        }
        cout<<ans;
    }
    /*
    6
    3 2 -1 1 -1 5
    
    8
    -5 -8 -23 -5 -6 -7 -12 -6 -7
    */
  • 相关阅读:
    COGNOS10启动服务报错 问题解决
    Linux 下 新增Oracle10g 实例 (转自http://www.cnblogs.com/lan0725/archive/2011/07/18/2109474.html)
    WIN7安装COGNOS8后配置IIS网站后,访问COGNOS站点网页一直显示空白,解决方法(转载)
    Gridview光棒效果 鼠标滑过
    11款实用的一句话网站设计代码
    自定义js方法 (格式化时间)
    测试一下
    UTF7转换GB2312编码的方法(中文)
    HTML注册页面验证注册信息
    android欢迎页
  • 原文地址:https://www.cnblogs.com/kamimxr/p/11438701.html
Copyright © 2011-2022 走看看