[51nod] 1050 循环数组最大子段和 dp

1050 循环数组最大子段和

N个整数组成的循环序列a[1],a[2],a[3],…,a[n],求该序列如a[i]+a[i+1]+…+a[j]的连续的子段和的最大值(循环序列是指n个数围成一个圈,因此需要考虑a[n-1],a[n],a[1],a[2]这样的序列)。当所给的整数均为负数时和为0。
例如:-2,11,-4,13,-5,-2,和最大的子段为:11,-4,13。和为20。
 
Input
第1行:整数序列的长度N(2 <= N <= 50000)
第2 - N+1行:N个整数 (-10^9 <= S[i] <= 10^9)
Output
输出循环数组的最大子段和。
Input示例
6
-2
11
-4
13
-5
-2
Output示例
20
 
最大循环字段和分两种情况:
1.正常的最大字段和 可用dp求
2.从后面某个元素开始,前面某个元素结束,此时中间会空出一段, 设sum(i,j)为这一段的和,sum为       整个数组的和,则maxsum = sum-sum(i,j) ,
 sum(i,j)最小时maxsum最大,即求最小子段和,  如果将数组取反,则最小子段和可转化为最大子段和,用相同的dp可解,再将结果取反就行了。
最终的结果是这两种情况的最大值
#include <iostream>
#include <stdio.h>
#include <algorithm>
using namespace std;
#define LL long long
#define MAX 50010
int N;
int a[MAX];

LL subSum()
{
    LL ans = 0, sum = 0;
    for (int i = 0; i < N; i++) {
        if (sum < 0)
            sum = a[i];
        else sum += a[i];
        ans = max(ans, sum);
    }

    return ans;
}

int main()
{
    //freopen("1.txt", "r", stdin);
    scanf("%d", &N);

    LL sum = 0;
    for (int i = 0; i < N; i++) {
        scanf("%d", &a[i]);
        sum += a[i];
    }

    LL ans1, ans2, ans;
    ans1 = subSum();
    for (int i = 0; i < N; i++)
        a[i] = -a[i];
    ans2 = subSum();
    ans = max(ans1, sum+ans2);

    printf("%lld
", ans);
    
    return 0;
}
原文地址:https://www.cnblogs.com/whileskies/p/7226288.html