容易想到:对于每个i,求出最大的第一个子段在区间[0,i]内和最大的第二个子段在区间[i+1,n-1]内再相加即可。
对于第一个子段的求法:
令p[i]表示以i结尾的子段的最大连续子段和,则显然有:
p[i] = max( a[i], a[i] + p[i - 1] );
求完以后再:
p[i] = max( p[i], p[i - 1] );
就可以得到含于区间[0,i]的最大子段和。
对于第二个子段的求法:
其实就是用这个方法再倒着求一遍。
最后求出答案即可。
1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 using namespace std; 5 6 const int N = 50000; 7 const int INF = -999999999; 8 int a[N], p[N], q[N]; 9 10 int main () 11 { 12 int t; 13 scanf("%d", &t); 14 while ( t-- ) 15 { 16 int n; 17 scanf("%d", &n); 18 for ( int i = 0; i < n; i++ ) scanf("%d", a + i); 19 p[0] = a[0]; 20 for ( int i = 1; i < n; i++ ) 21 { 22 p[i] = a[i]; 23 if( p[i - 1] > 0 ) 24 { 25 p[i] += p[i - 1]; 26 } 27 } 28 for ( int i = 1; i < n; i++ ) 29 { 30 p[i] = max( p[i], p[i - 1] ); 31 } 32 q[n - 1] = a[n - 1]; 33 for ( int i = n - 2; i >= 0; i-- ) 34 { 35 q[i] = a[i]; 36 if( q[i + 1] > 0 ) 37 { 38 q[i] += q[i + 1]; 39 } 40 } 41 for ( int i = n - 2; i >= 0; i-- ) 42 { 43 q[i] = max( q[i], q[i + 1] ); 44 } 45 int ans = INF; 46 for ( int i = 0; i < n - 1; i++ ) 47 { 48 ans = max( ans, p[i] + q[i + 1] ); 49 } 50 printf("%d\n", ans); 51 } 52 return 0; 53 }