染色

2026-10-09

问题概要

给你一个长为 \(n\) 的正整数序列 \(A = (A_1, \dots, A_n)\),从左到右排成一行。

你要将 \(A\) 的每个元素染成红色或蓝色,然后按下述方式计算每个 \(A_i\)(\(1 \le i \le n\))的得分:

求对序列 \(A\) 的一个染色方案中,\(A\) 的元素的得分之和可能达到的最大值。

你需要解决 \(T\) 组测试。

换个说法

把序列 \(A\) 切成若干段,然后按下述方式计算计算每个 \(A_i\) 的得分:

思路

考虑序列 \(a\) 的最后一项 \(a_n\),可见

考虑 DP。定义 \(f[i]\) 为序列 \((A_1, \dots, A_i)\) 的最大得分。若 \(A_i = A_{i-1}\) 则 \(f[i] = f[i - 1] + A_i\)。若 \(A_i \ne A_{i-1}\),考虑两种情况

对于第二种情况,若有多个满足条件的 \(j\),取哪一个呢?应当最大的那个。

证明:把满足上述条件的最大的 \(j\) 记作 \(j'\)。注意到

所以应当把 \(A_{j'}\) 和 \(A_{j'+1}\) 分开。

于是第二种情况进一步归结为计算下列两个东西

程序实现

点击展开代码
/**
 *    author:  zjs
 *    created: 09.10.2026 14:47:05
**/
#include <bits/stdc++.h>
#include <cassert> // <bits/stdc++.h> does not include cassert since GCC 16.
using namespace std;

#ifdef LOCAL
#include "debug.h"
#else
#define debug(...) 42
#endif

void solve() {
    int n;
    cin >> n;
    vector<int> a(n + 1);
    for (int i = 1; i <= n; i++)
        cin >> a[i];

    vector<int> last(1e6 + 5);
    vector<long long> f(n + 1);
    vector<long long> sum(n + 1);

    for (int i = 1; i <= n; i++) {
        if (a[i] == a[i - 1]) {
            f[i] = f[i - 1] + a[i];
        } else if (last[a[i]]) {
            int j = last[a[i]];
            f[i] = max(f[i - 1], f[j + 1] + sum[i - 1] - sum[j + 1] + a[i]);
        } else {
            f[i] = f[i - 1];
        }
        sum[i] = sum[i - 1] + (a[i] == a[i - 1]) * a[i];
        last[a[i]] = i;
    }
    cout << f[n] << '\n';
}

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    int T;
    cin >> T;
    while (T--) {
        solve();
    }
}