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;
}
分类:
题目总结
, 题目总结 / 2024. 10~12月
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现