N个整数组成的循环序列a[1],a[2],a[3],…,a[n],求该序列如a[i]+a[i+1]+…+a[j]的连续的子段和的最大值(循环序列是指n个数围成一个圈,因此需要考虑a[n-1],a[n],a[1],a[2]这样的序列)。当所给的整数均为负数时和为0。
例如:-2,11,-4,13,-5,-2,和最大的子段为:11,-4,13。和为20。
Input
第1行:整数序列的长度N(2 <= N <= 50000)
第2 - N+1行:N个整数 (-10^9 <= S[i] <= 10^9)
Output
输出循环数组的最大子段和。
Input示例
6
-2
11
-4
13
-5
-2
Output示例
20
直入正题:
答案只有两种可能性: 1:一段连续的字段和 2:一段在头,一段在尾
先说求情况1的方法吧:
假设从头开始,如果是负数就跳过,从下一个开始累加,判断和为负数中断,从断电开始累加,不断判断更新最大数字。说得有点抽象,举个例子:
-2,3,5,-7,9,-19,4,2,6,7
从-2开始,-2是负数,我选他会把和降低,我不如直接从3开始更好。
3+5=8-7=1+9=10-19=-9 为负数,中断,从4开始
4+2=6+6=12+7= 19 完毕,8,10,6,19中最大为19,所以最大为19,不用记录,算一次判断一次就可以了。
再说情况2:运用1的思路,求出最小字段和,总和减去这个最小字段和就是头尾最大的了。
情况1和2都算一遍,哪个大输出哪个,水过。
献上代码:
#include <iostream>
#include <cstdio>
using namespace std;
int main()
{
long long int n,a[50005],i,j,zsum=0,fsum=0,ma=0,fma=0,sum=0;
cin>>n;
for(i=0;i<n;i++)
{
cin>>a[i];
if(a[i]>ma)
ma=a[i];
if(a[i]<fma)
fma=a[i];
sum+=a[i];
}
for(i=0;i<n;i++)
{
zsum=a[i];
if(zsum<0)
continue;
for(j=i+1;j<n;j++)
{
zsum+=a[j];
if(zsum<0)
{
i=j;
break;
}
else if(zsum>ma)
ma=zsum;
}
}
for(i=0;i<n;i++)
{
fsum=a[i];
if(fsum>=0)
continue;
for(j=i+1;j<n;j++)
{
fsum+=a[j];
if(fsum>=0)
{
i=j;
break;
}
else if(fsum<fma)
fma=fsum;
}
}
if(ma>sum-fma)
cout<<ma;
else
cout<<sum-fma;
return 0;
}