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\n", ans); return 0; }