题目链接:戳一戳

题目:

做法:

首先要知道

不循环数组得最大子段和解法   戳一戳 链接

然后呢

循环数组的最大子段和有两种情况:

一是 和正常数组一样  求出最大字段和  ans1

二是  最大字段和不连续    a1+a2=sum    (后边+前边) 

这个时候就要把中间那段求出来 用总和减去 才是最大子段和

那么我们当然希望中间那段的值越小越好了  最小得到的子段和才是最大

所以我们求这个数组的最小子段和   怎么求最小子段和呢?  

(数组所有数字乘上 -1    然后按照求最大字段和的办法  求出最大字段和 

再把结果乘-1  就是最小子段和了)

用总和减去求得的最小子段和   得到的就是第二种情况的最大子段和  ans2

由于我们并不确定是那种情况  所以我们两种都算出来  取其中大的那个

ans=max(ans1,ans2)

代码:

#include<stdio.h>
#include<iostream>
#include<algorithm>
#include<string.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+7;
ll a[maxn];
ll b[maxn];
ll dp[maxn];
const ll INF=8e18;
ll n,sum;
int main(){
    scanf("%lld",&n);
    for(int i=1;i<=n;i++){scanf("%lld",&a[i]);sum+=a[i];}
    for(int i=1;i<=n;i++)b[i]=-a[i];
    memset(dp,0,sizeof(dp));
    ll maxx=0;
    for(int i=1;i<=n;i++){
        dp[i]=max(a[i],dp[i-1]+a[i]);
        maxx=max(dp[i],maxx);//记录最大连续子段和
    }
    memset(dp,0,sizeof(dp));
    ll m=0;
    for(int i=1;i<=n;i++){
        dp[i]=max(b[i],dp[i-1]+b[i]);
        m=max(dp[i],m);
    }
    if(sum+m>maxx)maxx=sum+m;
    printf("%lld\n",maxx);
}