Description
Input
Each test case contains two lines. The first line is an integer n(2<=n<=50000). The second line contains n integers: a1, a2, ..., an. (|ai| <= 10000).There is an empty line after each case.
Output
Sample Input
1 10 1 -1 2 2 3 -3 4 -4 5 -5
Sample Output
13
【FinkyS】
由于是要找两个不相交的子段,所以第一步先选定数列中的一个元素作为分界点。比如第i个元素,那么以选择第i个元素基础,此时要找的最大子段合就是第i个元素左边的最大子段以及右边的最大子段之和。假设用left[i]和right[i]来记录,那么left[i]从最左边即i=0开始,此时很容易知道left[0]=A[0],然后向右扫描即此时i=1,此时left[1]的值为left[0]和必定包含A[i]的左最大子段中较大的那一个,然后这里就遇到一个问题:要计算left[i]的值还必须知道必定包含A[i]的左最大子段的值。那么 先放弃直接找到最大字段,先用left[i]记录必定包含A[i]的最大左子段。经过观察可以知道:left[0]=A[0],left[1]=max{A[1],left[0]+A[1]}->left[i]=max{A[i],left[i-1]+A[i]},right[i]同理。然后左右扫描一次就可以记录下所有left[i]跟right[i]了。那么此时就可以解决上一个问题了。left[0]=A[0],left[1]=max{left[1],left[0]}->left[i]=max{left[i-1],left[i]};同理可知道:right[i]=max[right[i],right[i+1]];最后就可以得到最优解为for(int i=0,i<n-1;i++)MAX=max{MAX,left[i]+right[i+1]};
【Sky】
1.选定数列中的一个元素作为左右子段分界点。
2.以第i个元素A[i]为基础,此时的最优解为其最大左子段以及最大右子段之和。
3.用left[i]、right[i]记录最大(左/右)子段。
4.观察可知,left[0]=A[0],left[1]=max{left[0],必定包含A[1]的最大左子段}
5.遇到一个问题 要计算left[i]的值还必须知道必定包含A[i]的最大左子段的值。
6.先放弃直接找到最大字段,先用left[i]记录必定包含A[i]的最大左子段。
7.观察可知,left[0]=A[0],left[1]=max{left[0]+A[1],A[1]} -> left[i]=max{left[i-1]+A[i],A[i]}。 同理 right[i]=max{right[i+1]+A[i],A[i]}
8.扫描一次记录所有left[i]、right[i].
9.回到上一个问题,用left[i]、right[i]记录最大(左/右)子段。
10.观察可知,left[0]=A[0],left[1]=max{left[0],left[1]},left[i]=max{left[i-1],left[i]};同理 right[i]=max{right[i+1],right[i]}
11.最优解MAX为:for(int i=0,i<n-1;i++)MAX=max{MAX,left[i]+right[i+1]};
【实现代码】
#include<cstdio>
#include<cstdlib>
#include<cstring>
int A[50050];
int left[50050];
int right[50050];
int max(int a,int b)
{
return a>b?a:b;
}
int main()
{
/*
char STD[102400]="";
if(freopen("in.txt","r",stdin)==NULL)freopen("CON","r",stdin);
else
{
fread(STD,1,1024,stdin);
printf("===input===\n%s\n===output===\n",STD);
freopen("in.txt","r",stdin);
}
*/
int T;
scanf("%d",&T);
while(T--)
{
int n;
scanf("%d",&n);
for(int i=0;i<n;i++)scanf("%d",&A[i]);
for(int i=0;i<n;i++)
{
left[i]=A[i];
if(i!=0&&left[i-1]>0)left[i]+=left[i-1];
if(i>1)left[i-1]=max(left[i-1],left[i-2]);
}
for(int i=n-1;i>=0;i--)
{
right[i]=A[i];
if(i!=n-1&&right[i+1]>0)right[i]+=right[i+1];
if(i<n-2)right[i+1]=max(right[i+1],right[i+2]);
}
int MAX=0;
for(int i=0;i<n-1;i++)
{
if(i==0)MAX=left[i]+right[i+1];
else MAX=max(MAX,left[i]+right[i+1]);
}
printf("%d\n",MAX);
}
return 0;
}