思路
题目要求的是,两段不相交的连续子列,使其加和最大。基础问题就是最大连续子列和,只要分别求得正序和逆序的最大和,然后枚举一边中间点,就可以得到结果。
最大连续子列和
解法有多种,这里用一种比较简单的动规的方法。另一种思路
令
num[i]
表示序列中第 i 个数字,
F(i)
为以第 i 个数字结尾的序列中最大的和, 那么
F(1)=num[1] { F(i)=F(i−1)+num[i], F(i−1)>0 F(i)=num[i], F(i−1)<=0
根据题意,我们需要的
F(i)
是第 i 个数字之前的连续子列和的最大值,我们需要从头到尾更新一次
for(int i=2; i=n; i++) f(i) = max( f(i), f(i-2) );
代码
#include <iostream>
#include <cstdio>
#include <algorithm>
const int inf = 0x7ffffff;
using namespace std;
int num[50010], s[50010], e[50010];
int main()
{
int t, n, maxsum, sum;
scanf("%d", &t);
while(t--)
{
scanf("%d", &n);
for(int i=1; i<=n; i++) scanf("%d", num+i);
s[1] = num[1];
for(int i=2; i<=n; i++)
{
if(s[i-1]>0) s[i] = s[i-1] + num[i];
else s[i] = num[i];
}
for(int i=2; i<=n; i++) s[i] = max(s[i], s[i-1]);
e[n] = num[n];
for(int i=n-1; i>=1; i--)
{
if(e[i+1]>0) e[i] = e[i+1] + num[i];
else e[i] = num[i];
}
for(int i=n-1; i>=1; i--) e[i] = max(e[i+1], e[i]);
maxsum = -inf;
for(int i=1; i<n; i++)
{
sum = s[i] + e[i+1];
if(sum>maxsum) maxsum = sum;
}
printf("%d\n", maxsum);
}
}