N个整数组成的序列a[1],a[2],a[3],…,a[n],求该序列如a[i]+a[i+1]+…+a[j]的连续子段和的最大值。当所给的整数均为负数时和为0。
例如:-2,11,-4,13,-5,-2,和最大的子段为:11,-4,13。和为20。
Input
第1行:整数序列的长度N(2 <= N <= 50000)
第2 - N + 1行:N个整数(-10^9 <= A[i] <= 10^9)
Output
输出最大子段和。
Input示例
6
-2
11
-4
13
-5
-2
Output示例
20
分治法:
将序列分成1到(1+n)/2的序列与(1+n)/2到n的序列。那么最大的子段有可能出现在:
1.左侧序列。2.右侧序列。3.跨越中间点的序列。
我们从中间点两侧找最大子段,再找越过中间点的最大子段,得到复杂度为O(nlogn)的算法。
#include <iostream>
#include <cstdio>
using namespace std;
typedef long long LL;
LL a[50005];
LL Maxsum(LL *a,int left,int right)
{
LL maxsum=0;
if(left==right)
{
return (a[left]>0? a[left]:0);
}
LL mid=(left+right)/2;
LL leftsum=Maxsum(a,left,mid);
LL rightsum=Maxsum(a,mid+1,right);
LL lefts=0,rights=0,temps=0;
for(LL i=mid;i>=left;i--)
{
temps+=a[i];
if(temps>lefts) lefts=temps;
}
temps=0;
for(LL i=mid+1;i<=right;i++)
{
temps+=a[i];
if(temps>rights) rights=temps;
}
maxsum=lefts+rights;
if(leftsum>maxsum) maxsum=leftsum;
if(rightsum>maxsum) maxsum=rightsum;
return maxsum;
}
int main()
{
int n;
while(scanf("%d",&n)!=EOF)
{
for(int i=0;i<n;i++)
{
scanf("%lld",&a[i]);
}
LL ans=Maxsum(a,0,n-1);
printf("%lld\n",ans);
}
return 0;
}
dp:
#include <iostream>
#include <cstdio>
using namespace std;
typedef long long LL;
LL Maxsum(LL *a,int n)
{
LL sum=0,b=0;
for(int i=0;i<n;i++)
{
if(b>0)
{
b+=a[i];
}
else
{
b=a[i];
}
if(b>sum)
{
sum=b;
}
}
return sum;
}
int main()
{
int n;
LL a[50005];
while(scanf("%d",&n)!=EOF)
{
for(int i=0;i<n;i++)
{
scanf("%lld",&a[i]);
}
LL ans=Maxsum(a,n);
printf("%lld\n",ans);
}
return 0;
}