CF833B The Bakery 题解

一道简单 ds 优化 dp 题,下无特殊说明则 k 不是题目中的 k

朴素方程:设 fi,j 表示将 [1,i] 内的所有数划分成 j 段的方案数,那么有转移方程:

fi,j=max{fk,j1+val(k+1,i)ki}

也就是将 [k+1,i] 划成一段,val(k+1,i)k=i 时该值为 0) 表示 [k+1,i] 内不同 ai 数量,复杂度 O(n3k),如果 j 倒序枚举可以做到 O(n2k)(两个复杂度中的 k 是题中的 k),考虑优化。

先预处理一个 Prei 表示 aPrei=aiPrei 最大,那么只有满足 k[Prei+1,i]val(k+1,i) 会被影响到,有个 1 的贡献。

据此我们考虑先枚举 j[1,k] 为划分段数,然后对于 fi,j1 建线段树,线段树区间中 x 位置表示 fx,j1

根据上文所述,i 会影响到 k[Prei+1,i] 的 dp 值,于是我们先对区间 [Prei,i1] 区间加 1,左右端点减 1 的原因是转移方程的 valk 加了 1。

然后对于 fi,j 查询 [k1,i1](注意左端点不能是 1)内的最大值即可。

答案 fn,k(这个 k 和复杂度的 k 是题中的 k),初值全 0,复杂度 O(nklogn),没必要滚动数组。

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;
}
posted @   Plozia  阅读(112)  评论(2编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
点击右上角即可分享
微信分享提示