题目给一个整数序列,让你想象它们是首尾相连的一个圈,让你求一段,使得这段内的和最大。
Segment Sum 最大。
其实,这种Segment可以有2种情况——一种是,没有跨越头尾的;另一种是跨过头尾的。
前者,只需要用一个O(n)的经典dp就可以求出来。(思路就是,假如以上一位结尾的段和小于0,那么这一位就不必连续了,自己开个头算了。)
后者,转化成,求一个段和最小的,再用总和去减掉。
把所有数取相反数后,变成了求段和最大(哈哈,这时这个段和就变成了所求“最小段和”的相反数),再加上sum,与前者情况做比较,即可。
对了,一种特殊情况——所有数都是0,应该输出0的,特判一下就好了。
代码:
#include <cstdio>
using namespace std ;
#define maxn 200009
#define max(a,b) a>b?a:b
int t,n;
int a[maxn];
long long calc () {
long long sum = 0 , ans = -2119999999 ;
for ( int i = 0 ; i < n ; ++i ) {
sum += a[i] ;
if ( sum > ans ) ans = sum ;
if ( sum < 0 ) sum = 0 ;
}
return ans ;
}
int main () {
scanf ( "%d" , &t ) ;
while ( t-- ) {
scanf ( "%d" , &n ) ;
bool flag = 1 ;
long long maxx = -2119999999 , sum ;
for ( int i = 0 ; i < n ; ++i ) {
scanf ( "%d" , &a[i] ) ;
if ( a[i] >= 0 ) flag = 0 ;
if ( flag ) maxx = max ( maxx , a[i] ) ;
}
if ( flag ) {
printf ( "%lld\n" , maxx ) ;
continue ;
}
maxx = calc () , sum = 0 ;
for ( int i = 0 ; i < n ; ++i ) {
sum += a[i] ;
a[i] = -a[i] ;
}
printf ( "%lld\n" , max(maxx,sum+calc()) ) ;
//printf ( "DD %d" , c[m] ) ;
}
//system ( "pause" ) ;
return 0 ;
}