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


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