思路
先分别求出顺序和逆序时,仅考虑前$i$个且且以$a_i$结尾的连续子序列最大和,记为$f_i$、$fr_i$
同样分别顺序和逆序处理上步得到的状态数组,改造为“仅考虑前$i$个但不限制$a_i$结尾的连续子序列最大和”
枚举分界点,将数组分为两段$a_1 \sim a_k$、$a_{k+1} \sim a_n$,根据状态数组求左段顺序最大和$f_k$、右段逆序最大和$fr_{k+1}$
代码
import java.util.*;
import java.lang.*;
public class Main {
static Scanner scanner = new Scanner(System.in);
static int t, n, N = 50010;
static long[] a = new long[N], f = new long[N], fr = new long[N];
public static void main(String[] args) {
t = scanner.nextInt();
for (int k = 1; k <= t; k++) {
Arrays.fill(f, 0); // 状态初始化
Arrays.fill(fr, 0);
n = scanner.nextInt();
for (int i = 1; i <= n; i++) a[i] = scanner.nextInt(); // 读数
// 顺序求 只考虑前i个且以a[i]结尾的连续子序列最大和
for (int i = 1; i <= n; i++) f[i] = Math.max(0, f[i - 1]) + a[i];
// 逆序求 只考虑后i个·····
for (int i = n; i >= 1; i--) fr[i] = Math.max(0, fr[i + 1]) + a[i];
// 顺序遍历 将状态数组改为 “只考虑前i个数,能得到的连续子序列最大和”
for (int i = 2; i <= n; i++) f[i] = Math.max(f[i], f[i - 1]);
// 逆序遍历 ····
for (int i = n - 1; i >= 1; i--) fr[i] = Math.max(fr[i], fr[i + 1]);
long res = Long.MIN_VALUE;
// 枚举分界点 将数组分为顺序【1,i】、逆序【i+1,n】两段 两段最大和相加即为最终答案
for (int i = 1; i < n; i++) res = Math.max(res, f[i] + fr[i + 1]);
System.out.println(res);
}
}
}