分析:
(1)笨方法,我们可以用普通最大子段和的方法解决这个问题。我们从每个位置“断开”环,然后按普通的最大子段和的方法去做。这样做的复杂度是O(n^2)。
(2)巧妙点的方法,我们之所以要从某个位置切开是因为循环的最大子段和可能是跨越一部分头和尾。
如上图,最优解可能是0..i, j + 1.. n – 1两段,那这时,其实中间i + 1..j是个“最小子段和”,因为总和是一定得嘛。
所以“循环数组得最大子段和”问题,可以把环从任意位置断开,然后求出最优解 = max(普通的最大子段和, 总和 – 普通的“最小子段和”)
求最小子段和,显然也可以用最大子段和的方法求一次就可以了。所以循环数组的最大子段和,实际上是求了两次最大子段和而已。
(1)笨方法,我们可以用普通最大子段和的方法解决这个问题。我们从每个位置“断开”环,然后按普通的最大子段和的方法去做。这样做的复杂度是O(n^2)。
(2)巧妙点的方法,我们之所以要从某个位置切开是因为循环的最大子段和可能是跨越一部分头和尾。

如上图,最优解可能是0..i, j + 1.. n – 1两段,那这时,其实中间i + 1..j是个“最小子段和”,因为总和是一定得嘛。
所以“循环数组得最大子段和”问题,可以把环从任意位置断开,然后求出最优解 = max(普通的最大子段和, 总和 – 普通的“最小子段和”)
求最小子段和,显然也可以用最大子段和的方法求一次就可以了。所以循环数组的最大子段和,实际上是求了两次最大子段和而已。
ACcode:
#include <map>
#include <queue>
#include <cmath>
#include <cstdio>
#include <cstring>
#include <stdlib.h>
#include <iostream>
#include <algorithm>
#define maxn 50005
#define ll long long
using namespace std;
int n,m;
ll c[maxn];
ll max_ans,min_ans,tmp,sum;
int main(){
while(~scanf("%d",&n)){
for(int i=1;i<=n;++i)scanf("%I64d",&c[i]);
sum=tmp=0;
for(int i=1;i<=n;++i){
if(tmp>0)tmp+=c[i];
else tmp=c[i];
sum+=c[i];
max_ans=max_ans>tmp?max_ans:tmp;
}
tmp=0;
for(int i=1;i<=n;++i){
if(tmp<0)tmp+=c[i];
else tmp=c[i];
min_ans=min_ans<tmp?min_ans:tmp;
}
printf("%I64d\n",max(max_ans,sum-min_ans));
}
return 0;
}