P11233 [CSP-S 2024] 染色

前言: 考场上只写了暴力, 20pts, 现在想了想还是挺亏的. (不过考场上我应该也想不出来, 今年又得寄.

题面

看见这个题目, \(20pts\) 直接暴力 \(dfs\) 就行(考场上就这么写的).

接下来考虑 \(dp\).

\(f_i\) 表示考虑到第 \(i\) 个数的时候的最大贡献.

显然 \(f_i\) 可以初始化为 \(f_{i-1}\).

再用一个 \(lst_i\) 记录 \(a_i\) 上一次出现的位置, 每次动态地更新 \(lst_{a_i} = i\).

这样时间复杂度是 \(\mathcal{O}(n^2)\) 的, 无法通过, 接下来考虑优化.

发现可以使用前缀和进行优化.
每当 \(a_i = a_{i-1}\) 时, 更新 \(s_i\), 否则 \(s_i = s_{i-1}\).

接下来就是转移了, 当 \(\exists lst_{a_i}\) 时, 转移方程如下:

\[f_i = \max_{i = 1}^n (f_{lst_{a_i}+1} + a_i + s_i - s_{lst_{a_i} + 1}) \]

最后答案即为 \(f_n\).

时间复杂度 \(\mathcal{O}(n)\), 足够通过此题.

更多的解释放在代码里面了.

#include "iostream"
#include "cstring"

using namespace std;

typedef long long ll;

const int N = 1e6 + 10;

int T;
int n, a[N];
ll f[N], s[N];
int lst[N];

inline void init()
{
    memset(a, 0, sizeof a);
    memset(f, 0, sizeof f);
    memset(s, 0, sizeof s);
    memset(lst, 0, sizeof lst);
}

int main()
{

    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cout.tie(nullptr);

    cin >> T;
    while (T--)
    {

        init();

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

        for (int i = 2; i <= n; ++i) s[i] = s[i - 1] + a[i] * (a[i] == a[i - 1]);

        for (int i = 1; i <= n; ++i)
        {
            f[i] = f[i - 1];
            if (lst[a[i]]) 
                f[i]=max(f[i], f[lst[a[i]] + 1] + a[i] + s[i] - s[lst[a[i]] + 1]); 
                /*贡献分三段, 第一段是从 1 ~ lst[a[i]] + 1 (即 f[lst[a[i]] + 1]), 
                第二段是前缀和计算的 lst[a[i]] + 1 ~ i 的贡献, 第三段即为 a[i] 本身.*/
            lst[a[i]] = i;
        }

        cout << f[n] << endl;

    }

    return 0;
}
posted @   Steven1013  阅读(3)  评论(0编辑  收藏  举报
(评论功能已被禁用)
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示