• 洛谷 P1121 环状最大两段子段和 题解


    每日一题 day57 打卡

    Analysis

    对于这个问题,由于分成了两个子序列,我们不妨就是枚举一下可能出现的情况:

    无非就这两种:

    1.+++++0000+++++0000++++

    2.0000++++00000++++000000

    0就表示选了这个数,+就表示不选这个数,

    那我们正反先做一个普通的最大子序列,就可以完成第2中情况,然后再求个最小子序列,把总和一减就是第1种情况。

    至于求最小子序列,可以把数字都负过来,然后再搞个最大子序列就好了。

    楼下举的例子非常对,我仔细思考了一下这个特例,即

    4 -1 1 -1 -1

    当我们将数字负过来时,就成了:

    4 1 -1 1 1

    此时的两个最大子序列我们会选成:

    0+00 而首尾都选了,其实就是只选了一个序列,而这种特殊情况又只会在

    只有一个数是正数时出现,所以特判一下就好了,如果只有一个数是正数,我们就不做将数字负过来后的那个最大子序列了,

    直接找两个最大的数累和就行了。

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #define int long long
     6 #define maxn 200000+10
     7 #define INF 2147483647
     8 #define rep(i,s,e) for(register int i=s;i<=e;++i)
     9 #define dwn(i,s,e) for(register int i=s;i>=e;--i)
    10 using namespace std;
    11 inline int read()
    12 {
    13     int x=0,f=1;
    14     char c=getchar();
    15     while(c<'0'||c>'9') {if(c=='-') f=-1; c=getchar();}
    16     while(c>='0'&&c<='9') {x=x*10+c-'0'; c=getchar();}
    17     return f*x;
    18 }
    19 inline int write(int x)
    20 {
    21     if(x<0) {putchar('-'); x=-x;}
    22     if(x>9) write(x/10);
    23     putchar(x%10+'0');
    24 }
    25 int n,sum1,sum2;
    26 int a[maxn],dp_top[maxn],dp_back[maxn];
    27 inline int calc()
    28 {
    29     int res=-INF;
    30     rep(i,1,n) dp_top[i]=max(dp_top[i-1],0ll)+a[i];
    31     dwn(i,n,1) dp_back[i]=max(dp_back[i+1],0ll)+a[i];
    32     rep(i,1,n) dp_top[i]=max(dp_top[i-1],dp_top[i]);
    33     dwn(i,n,1) dp_back[i]=max(dp_back[i+1],dp_back[i]);
    34     rep(i,1,n-1) res=max(res,dp_top[i]+dp_back[i+1]);
    35     return res;
    36 }
    37 signed main()
    38 {
    39     memset(a,128,sizeof(a));
    40     n=read();
    41     rep(i,1,n) 
    42     {
    43         a[i]=read();
    44         sum1+=a[i];
    45         if(a[i]>0) sum2+=a[i];
    46     }
    47     if(sum2==0)
    48     {
    49         int minn1=-INF,num=0;
    50         rep(i,1,n) 
    51         {
    52             if(a[i]>minn1)
    53             {
    54                 minn1=a[i];
    55                 num=i;
    56             }
    57         }
    58         a[num]=-INF;
    59         int minn2=-INF;
    60         rep(i,1,n) 
    61             if(a[i]>minn2) minn2=a[i];
    62         write(minn1+minn2);
    63         return 0;
    64     }
    65     int ans1=calc();
    66     rep(i,1,n) a[i]=-a[i];
    67     int ans2=sum1+calc();
    68     if(ans2==0) ans2=-INF;
    69     write(max(ans1,ans2));
    70     return 0;
    71 }

    请各位大佬斧正(反正我不认识斧正是什么意思)

  • 相关阅读:
    MySQL聚集索引和非聚集索引
    如何避免表单重复提交
    i++为什么是线程不安全的
    TIME_WAIT和CLOSE_WAIT
    TCP三次握手四次挥手
    get和post区别
    Session存储
    Session和Cookie的区别和联系
    Servlet与线程安全
    AQS
  • 原文地址:https://www.cnblogs.com/handsome-zyc/p/12024045.html
Copyright © 2020-2023  润新知