洛谷 P17728 [SCP-J 2026] 染色 / color 题解
洛谷 P17728 [SCP-J 2026] 染色 / color 题解
前言
昨天打 SCP-J 2026 时,这道题只得了 76pts,写一篇题解来祭奠我可怜的 176pts。
思路分析
原题传送门:洛谷 P17728 [SCP-J 2026] 染色 / color
若将 \(\left[A_{1},A_{n}\right]\) 全部染成红色,则得分如下:
通过上面的例子,可以发现一个结论:
将一段区间染成同一个颜色,其得分为最后一个数减去第一个数,不管区间是否连续。
若整个数组全部染成红色,则得分为 \(A_n-A_1\),所以我们将 \(ans\) 初始化为 \(A_n-A_1\)。
若将这个数组染成两种不同的颜色(不妨假设将数组开头染成红色),设蓝色区间的首项为 \(A_k\),从 \(2\) 到 \(n\) 枚举这个 \(k\)。
情况 1
若将数组结尾染成蓝色,则设红色区间的尾项为 \(A_m\),则得分为 \(\left(A_m-A_1\right)+\left(A_n-A_k\right)\)。我们只需要找到 \(A_m\) 的最大值。
红色区间的尾项 \(A_m\) 既可以在 \(A_{k-1}\),也可以在 \(\left[A_{k+1},A_{n-1}\right]\) 区间内,所以 \(A_m\) 的最大值为 \(\displaystyle\max(A_{k-1},\max_{k+1\leq i\leq n-1} A_i)\)。
情况 2
若将数组结尾染成红色,则设蓝色区间的尾项为 \(A_m\),则得分为 \(\left(A_n-A_1\right)+\left(A_m-A_k\right)\),所以也要找到最小的 \(A_m\)。
当蓝色区间只有一项时,\(A_m\) 在 \(A_k\) 的位置;当蓝色区间有多项时,\(A_m\) 在 \(\left[A_{k+1},A_{n-1}\right]\) 区间内。所以 \(A_m\) 的最大值为 \(\displaystyle\max(A_k,\max_{k+1\leq i\leq n-1}A_i)\)。
注意:因为要将数组结尾染成红色,所以蓝色区间的起点必须在 \(A_n\) 之前,即 \(k<n\)。
代码实现
这里可以使用后缀最大值数组维护 \(\max A_i\)。时间复杂度为 \(O(n)\)。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int a[200005], maxn[200005];
int n;
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
memset(maxn, 128, sizeof(maxn)); // 将数组初始化为一个接近 int 类型下限的负数
for (int i = n - 1; i >= 1; i--)
maxn[i] = max(maxn[i + 1], a[i]);
int ans = a[n] - a[1]; // 全部染一种颜色
for (int k = 2; k <= n; k++) {
// 分类讨论
// 情况一:数组头尾染色不同
int maxa = max(a[k - 1], maxn[k + 1]);
ans = max(ans, (a[n] - a[k]) + (maxa - a[1]));
// 情况二:数组头尾染色相同
if (k < n) {
maxa = max(a[k], maxn[k + 1]);
ans = max(ans, (a[n] - a[1]) + (maxa - a[k]));
}
}
printf("%d\n", ans);
return 0;
}
代码简化
这里,我们不难发现,代码里有很多重复的部分。\(A_m\) 其实就是在算 \(\displaystyle\max_{k-1\leq i\leq n-1}\)。所以我们实际上可以大大简化代码。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int a[200005], maxn[200005];
int n;
int main() {
scanf("%d", &n);
for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
memset(maxn, 128, sizeof(maxn)); // 将数组初始化为一个接近 int 类型下限的负数
for (int i = n - 1; i >= 1; i--)
maxn[i] = max(maxn[i + 1], a[i]);
int ans = a[n] - a[1]; // 全部染一种颜色
for (int k = 2; k <= n; k++)
ans = max(ans, a[n] - a[1] + maxn[k - 1] - a[k]);
printf("%d\n", ans);
return 0;
}

浙公网安备 33010602011771号