题解 P11233【[CSP-S 2024] 染色】
题目描述
给定一个长度为 \(n\) 的正整数数组 \(A\),其中所有数从左至右排成一排。
你需要将 \(A\) 中的每个数染成红色或蓝色之一,然后按如下方式计算最终得分:
设 \(C\) 为长度为 \(n\) 的整数数组,对于 \(A\) 中的每个数 \(A_i\)(\(1 \leq i \leq n\)):
- 如果 \(A_i\) 左侧没有与其同色的数,则令 \(C_i = 0\)。
- 否则,记其左侧与其最靠近的同色数为 \(A_j\),若 \(A_i = A_j\),则令 \(C_i = A_i\),否则令 \(C_i = 0\)。
你的最终得分为 \(C\) 中所有整数的和,即 \(\sum \limits_{i=1}^n C_i\)。你需要最大化最终得分,请求出最终得分的最大值。
对于所有测试数据,保证:\(1\leq T\leq 10\),\(2\leq n\leq 2\times 10^5\),\(1\leq A_i\leq 10^6\)。
solution
两种颜色是没有区别的。\(f_{i, j}\) 表示一种颜色最后一个选的是 \(i\),另一种颜色最后一个选的是 \(j\),要求 \(j<i\)。转移枚举 \(i+1\) 与 \(i, j\) 中的哪一个同色。转移到 \(f_{i+1, j}\) 和 \(f_{i+1, i}\) 中的一个。仔细考虑也就是
\[f_{i, j}+[a_i=a_{i+1}]a_{i+1}\to f_{i+1, j}
\]
\[f_{i, j}+[a_j=a_{i+1}]a_{i+1}\to f_{i+1, i}
\]
将 \(i\) 这一维去掉,第一种转移是全局加(直接维护标记),第二种转移是单点修改(事实上甚至是 push_back
,不会影响其它已计算的值),需要支持查询全局最大值和 \(a_j=a_{i+1}\) 的 \(f_j\) 的最大值,前者用一个变量维护,后者开一个桶维护。我写的复杂度是 \(O(T(n+V))\)。
code
#include <bits/stdc++.h>
using namespace std;
#ifdef LOCAL
#define debug(...) fprintf(stderr, ##__VA_ARGS__)
#else
#define debug(...) void(0)
#define endl "\n"
#endif
using LL = long long;
template <class T> T& cmax(T& x, const T& y) { return x = max(x, y); }
template <class T> T& cmin(T& x, const T& y) { return x = min(x, y); }
int n, a[200010];
LL buc[1000010];
int mian() {
cin >> n;
for (int i = 1; i <= n; i++) cin >> a[i];
memset(buc, ~0x3f, sizeof buc);
LL tag = 0, mx = 0;
buc[0] = 0;
for (int i = 2; i <= n; i++) {
LL val = max(mx, buc[a[i]] + tag + a[i]);
if (a[i] == a[i - 1]) tag += a[i], mx += a[i];
cmax(mx, val), cmax(buc[a[i - 1]], val - tag);
}
cout << mx << endl;
return 0;
}
int main() {
#ifndef LOCAL
#ifdef NF
freopen("color.in", "r", stdin);
freopen("color.out", "w", stdout);
#endif
cin.tie(nullptr)->sync_with_stdio(false);
#endif
int t;
cin >> t;
while (t--) mian();
return 0;
}
本文来自博客园,作者:caijianhong,转载请注明原文链接:https://www.cnblogs.com/caijianhong/p/18526012/solution-P11233