CF833B The Bakery 题解
一道简单 ds 优化 dp 题,下无特殊说明则 不是题目中的 。
朴素方程:设 表示将 内的所有数划分成 段的方案数,那么有转移方程:
也就是将 划成一段,( 时该值为 0) 表示 内不同 数量,复杂度 ,如果 倒序枚举可以做到 (两个复杂度中的 是题中的 ),考虑优化。
先预处理一个 表示 且 最大,那么只有满足 的 会被影响到,有个 1 的贡献。
据此我们考虑先枚举 为划分段数,然后对于 建线段树,线段树区间中 位置表示 。
根据上文所述, 会影响到 的 dp 值,于是我们先对区间 区间加 1,左右端点减 1 的原因是转移方程的 中 加了 1。
然后对于 查询 (注意左端点不能是 1)内的最大值即可。
答案 (这个 和复杂度的 是题中的 ),初值全 0,复杂度 ,没必要滚动数组。
GitHub:CodeBase-of-Plozia
Code:
/*
========= Plozia =========
Author:Plozia
Problem:CF833B The Bakery
Date:2022/4/29
========= Plozia =========
*/
#include <bits/stdc++.h>
typedef long long LL;
const int MAXN = 3.5e4 + 5;
int n, k, a[MAXN], f[MAXN][55], Pre[MAXN], book[MAXN];
struct node
{
int tag, Maxn;
}tree[MAXN << 2];
#define tag(p) tree[p].tag
#define Maxn(p) tree[p].Maxn
int Read()
{
int sum = 0, fh = 1; char ch = getchar();
for (; ch < '0' || ch > '9'; ch = getchar()) fh -= (ch == '-') << 1;
for (; ch >= '0' && ch <= '9'; ch = getchar()) sum = sum * 10 + (ch ^ 48);
return sum * fh;
}
int Max(int fir, int sec) { return (fir > sec) ? fir : sec; }
int Min(int fir, int sec) { return (fir < sec) ? fir : sec; }
void Update(int p) { Maxn(p) = Max(Maxn(p << 1), Maxn(p << 1 | 1)); }
void Spread(int p)
{
if (tag(p))
{
Maxn(p << 1) += tag(p); Maxn(p << 1 | 1) += tag(p);
tag(p << 1) += tag(p); tag(p << 1 | 1) += tag(p);
tag(p) = 0;
}
}
void Change(int p, int x, int v, int lp, int rp)
{
tag(p) = 0; if (lp == rp) { Maxn(p) = v; return ; }
int mid = (lp + rp) >> 1;
if (x <= mid) Change(p << 1, x, v, lp, mid);
else Change(p << 1 | 1, x, v, mid + 1, rp);
Update(p);
}
void Add(int p, int l, int r, int v, int lp, int rp)
{
if (lp >= l && rp <= r) { Maxn(p) += v; tag(p) += v; return ; }
Spread(p); int mid = (lp + rp) >> 1;
if (l <= mid) Add(p << 1, l, r, v, lp, mid);
if (r > mid) Add(p << 1 | 1, l, r, v, mid + 1, rp);
Update(p);
}
int Ask(int p, int l, int r, int lp, int rp)
{
if (lp >= l && rp <= r) return Maxn(p);
Spread(p); int mid = (lp + rp) >> 1, val = 0;
if (l <= mid) val = Max(val, Ask(p << 1, l, r, lp, mid));
if (r > mid) val = Max(val, Ask(p << 1 | 1, l, r, mid + 1, rp));
return val;
}
int main()
{
n = Read(), k = Read(); for (int i = 1; i <= n; ++i) a[i] = Read();
for (int i = 1; i <= n; ++i)
{
if (!book[a[i]]) book[a[i]] = i;
else { Pre[i] = book[a[i]]; book[a[i]] = i; }
}
for (int j = 1; j <= k; ++j)
{
for (int i = 1; i <= n; ++i) Change(1, i, f[i][j - 1], 0, n);
for (int i = 1; i <= n; ++i)
{
Add(1, Pre[i], i - 1, 1, 0, n);
f[i][j] = Ask(1, j - 1, i - 1, 0, n);
}
}
printf("%d\n", f[n][k]); return 0;
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具