Sicily 1888. Circular Sequence

題目給一個整數序列,讓你想象它們是首尾相連的一個圈,讓你求一段,使得這段內的和最大。

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 ;
} 


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章