洛谷 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 }

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

原文地址:https://www.cnblogs.com/handsome-zyc/p/12024045.html