蓝桥杯 2026 省 A 综合应变指标 题解
Description
给定长度为 \(N\) 的整数序列 \(A_1, A_2, \dots, A_N\)。将该序列拆分为 \(4\) 个连续非空子段:
- \(A_1,\dots,A_i\)
- \(A_{i+1}\dots,A_j\)
- \(A_{j+1},\dots,A_k\)
- \(A_{k+1},\dots,A_N\)
其中,\(1\le i< j<k < N\)。
试求 \(\displaystyle \left\lvert{A_1+\dots+A_i}\right\rvert+\left\lvert{A_{i+1}+\dots+A_j}\right\rvert+\left\lvert{A_{j+1}+\dots+A_k}\right\rvert+\left\lvert{A_{k+1}+\dots+A_N}\right\rvert\) 的最大值。
Solution
看到连续子段和,立即想到前缀和。前缀和用 \(S\) 表示,则目标式可化为
观察上式,如果固定 \(j\),那么前两项只与 \(i\) 有关,后两项只与 \(k\) 有关,且 \(i\) 和 \(k\) 的选择相互独立。
因此,对于每个 \(j\),我们可以分别求出:
那么答案就是 \(\max\limits_{2\le j\le N-2} \big( L_j + R_j \big)\)。
接下来讨论如何快速计算 \(L_j\) 和 \(R_j\)。只分析 \(L_j\),\(R_j\) 类似处理即可。
对于 \(L_j = \max_{1\le i<j} \big( |S_i| + |S_j - S_i| \big)\),令 \(x = S_i\),\(c = S_j\),则我们需要在 \(x\) 的取值集合 \(\{S_1, S_2, \dots, S_{j-1}\}\) 中最大化:
函数 \(h(x)\) 的几何意义是数轴上点 \(x\) 到 \(0\) 和到 \(c\) 的距离之和。这是一个下凸函数,下凸函数在闭区间上的最大值一定出现在区间端点。于是,\(h(x)\) 的最大值必然在 \(x\) 取最小值或最大值时取到。
因此,我们只需考虑左边部分的前缀和最大值 \(\text{pre_mx}_{j-1}\) 和最小值 \(\text{pre_mn}_{j-1}\),依下式即得 \(L_j\)。
本算法时间复杂度 \(O(N)\)。
Code
#include <bits/stdc++.h>
typedef long long i64;
using namespace std;
const int MAXN = 1e5;
i64 ans, sum[MAXN + 1];
i64 pre_mx[MAXN + 1], pre_mn[MAXN + 1], suf_mx[MAXN + 1], suf_mn[MAXN + 1];
int main()
{
int n;
scanf("%d", &n);
for (int i = 1; i <= n; ++i)
{
scanf("%lld", sum + i);
sum[i] += sum[i - 1];
}
pre_mx[1] = pre_mn[1] = sum[1];
for (int i = 2; i <= n; ++i)
{
pre_mx[i] = max(pre_mx[i - 1], sum[i]);
pre_mn[i] = min(pre_mn[i - 1], sum[i]);
}
suf_mx[n] = suf_mn[n] = sum[n] - sum[n - 1];
for (int i = n - 1; i >= 1; --i)
{
suf_mx[i] = max(suf_mx[i + 1], sum[n] - sum[i - 1]);
suf_mn[i] = min(suf_mn[i + 1], sum[n] - sum[i - 1]);
}
for (int j = 2; j <= n - 2; ++j)
{
i64 cand1_L = abs(pre_mx[j - 1]) + abs(sum[j] - pre_mx[j - 1]);
i64 cand2_L = abs(pre_mn[j - 1]) + abs(sum[j] - pre_mn[j - 1]);
i64 L = max(cand1_L, cand2_L);
i64 cand1_R = abs(suf_mx[j + 2]) + abs(sum[n] - sum[j] - suf_mx[j + 2]);
i64 cand2_R = abs(suf_mn[j + 2]) + abs(sum[n] - sum[j] - suf_mn[j + 2]);
i64 R = max(cand1_R, cand2_R);
ans = max(ans, L + R);
}
printf("%lld\n", ans);
return 0;
}
Addition
如果拆分出的子段数量更多,上述方法便不再适用。我们可以使用更高级的算法解决此类区间分拆问题,详见OI Wiki。

浙公网安备 33010602011771号