Constraints
Time Limit: 1 secs, Memory Limit: 32 MB
Description
Given a set of n integers: A={a1, a2,..., an}, we define a function d(A) as below:
t1 t2
d(A) = max{ ∑ai + ∑aj | 1 <= s1 <= t1 < s2 <= t2 <= n }
i=s1 j=s2
Your task is to calculate d(A).
Input
The input consists of T(<=30) test cases. The number of test cases (T) is given in the first line of the input.
Each test case contains two lines. The first line is an integer n(2<=n<=50000). The second line contains n integers: a1, a2, ..., an. (|ai| <= 10000)
Output
Print exactly one line for each test case. The line should contain the integer d(A).
Sample Input
1 10 1 -1 2 2 3 -3 4 -4 5 -5
Sample Output
13
Solution
题意就是给出一个序列,求序列中最大的两段和,这两个连续子序列可以连续,就是一个连续子序列。
一开始看觉得是最长上升子序列的变形,后来有人说可以划分成两个子问题,就是求左边的最长上升子序列和右边的最长上升子序列的和,枚举划分点。
瞬间就有思路了~!另外右边的可以不求出具体的和,只需要求出右边序列中每一个元素的以该元素结尾的最大和即可。
dp_r[i]表示从右边开始,以第i个元素结尾的最大连续和
dp_l[i]表示从左边开始,以第i个元素结尾的最大连续和
get_l[i]表示左边序列到第i个元素的最大连续和
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
int dp_r[50005], dp_l[50005], get_l[50005], a[50005];
int main()
{
int t;
scanf("%d", &t);
while (t--)
{
int i, j, n, temp, ans;
scanf("%d", &n);
for (i = 1; i <= n; ++i)
{
scanf("%d", &a[i]);
dp_l[i] = max(dp_l[i-1]+a[i], a[i]);
if (i == 1) get_l[i] = dp_l[i]; //左边最长上升子序列的和
else get_l[i] = max(get_l[i-1], dp_l[i]);
}
dp_r[n+1] = 0;
for (i = n; i > 1; --i) //枚举划分点
{
dp_r[i] = max(dp_r[i+1]+a[i], a[i]);
if (i == n) ans = dp_r[i] + get_l[i-1];
else ans = max(ans, dp_r[i]+get_l[i-1]);
}
printf("%d\n", ans);
}
return 0;
}