題目給一個整數序列,讓你想象它們是首尾相連的一個圈,讓你求一段,使得這段內的和最大。
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 ;
}