[CodeForces] CF558 题解

注:难度评级为 D 到 A,对标 NOIP T1 到 T4。+ 表示比原本难,- 反之。例如,D+ 比 D 难。难度评级仅供参考。 如果认为难度评级与实际难度不符,可以在评论区@我进行讨论。

本篇题解无复杂的公式推导,题目较清新自然,请放心食用。

斜体字为说明提示。通常与多倍经验有关。


A. Lala Land and Apple Trees

Link-CF
Link-Luogu

【难度分析】

思维难度:D-
实现难度:D-
总体难度:D-
评级: 普及-

【题目大意】

一个人,最初在数轴 0 点,每次可以选择一个方向走,走到苹果树的位置 xi,获得 ai 价值,然后掉头。一直走,直到他走到方向没有苹果树。一共有 n 颗苹果树。

  • 1n100105xi105xi01ai105

【解题思路】

考虑贪心。

显然,应该选择苹果树较多的那个方向走。最后得到的苹果总数是 min()+1。使用 vector 存储信息,排序后统计即可。


B. Amr and The Large Array

Link-CF
Link-Luogu

【难度分析】

思维难度:D-
实现难度:D-
总体难度:D-
评级: 普及/提高-

难度解析:此题的难度瓶颈在于理解题意。

【题目大意】

注意:洛谷上的题目翻译不准确。

定义一个序列的美丽值 f(A),为在序列 A 中,出现次数最多的数的出现次数

形式化地,有

f(A)=max1in(j=1n[Ai=Aj])

其中,n 是序列 A 的长度。[](方括号)表示,如果它内部的表达式为真,那么值为 1,否则为 0

现在,给定你序列 A,你需要求出 A 的一个连续的子段 B,使得 f(A)=f(B)。如果 BA 中的位置为 [l,r],你只需要输出 lr

  • 1n1051ai106

【解题思路】

容易知道,我们需要选取出现次数最多的数,所以只需要枚举出现次数最多的数。由于我们要使答案最小,我们可以取 l 为这个数最左端的位置,r 为这个数最右端的位置,这样一定是长度最小的。


C. Amr and Chemistry

Link-CF
Link-Luogu

【难度分析】

思维难度:C+
实现难度:C-
总体难度:C
评级: 普及+/提高

难度解析:此题对标三值逻辑。

【题目大意】

n 个数,第 i 个数为 ai,你可以对每个数进行一下操作:

  • 将一个数乘二。
  • 将一个数除以二并向下取整。

问最少通过多少次操作可以将这些数变得相同。

  • 1n1051ai105

【解题思路】

第一个操作相当于在数的二进制的末尾补 0,第二个数相当于去掉末尾的数。

这样,我们可以直接使用 01-Trie。末尾补 0 相当于向 0 儿子走,去掉末尾相当于走到父亲节点。

于是问题变成:一棵树上,每次可以走向 0 儿子或者父亲,你需要确定一个点,使得所有有标记的点到这个点走的步数和最小。这里的有标记的点是指 ai 的末尾在 01-Trie 上的编号。

那这就是一个经典换根 DP 了。设 fi 为所以有标记的点走到 i 的最小步数,gii 子树内有标记的点的个数,那么有

fv=fu+n2gv

解释:其中,vu 的子节点。我们 v 的子树内所有节点,共 gv 个,从走到 u 变成了走到 v,那么显然少走了一步,要减去 gv。但其他节点都多走了一步,所以要加上 ngv

其实这种换根 DP 技巧与这道题完全一样。

实现方法:第一次 DFS 求出 g,第二次 DFS 求出 f。第二次 DFS 只能向 0 儿子递归,因为只能末尾补 0 不能末尾补 1。且第二次 DFS 时,根节点不是原来字典树的根节点。这个根节点是所有节点的 LCA。为什么?因为变到 LCA 就不用变了。

注意 ai 可重复。注意根节点的 f 的初始值。


D. Guess Your Way Out! II

Link-CF
Link-Luogu

【难度分析】

思维难度:B
实现难度:C+
总体难度:B-
评级: 省选/NOI-

【题目大意】

一颗完美二叉树,根节点编号为 1。第 i 个点左儿子编号为 2×i,右儿子编号为 2×i+1。根节点为第一层,儿子节点的层数在它的父亲节点的基础上增加 1

你需要求出一个叶子节点(叶子节点层数为 h),给你 q 个信息:

每次信息形如 i,L,R,o,表示该节点的层数为 i 的祖先的编号是否在区间 [L,R] 内,是则 o=1,否则 o=0

如果无法找到一个这样的节点,输出 Game cheated!;如果有多个这样的节点,输出 Data not sufficient!;如果有且仅有一个这样的节点,输出节点编号。

  • 1h501q105,保证信息合法。

【解题思路】

考虑到在树上进行区间操作是一件很困难的事,所以应该把它转化到序列上。

具体来说,给定深度为 i 的区间 [L,R],容易求出它在叶子节点那一层对应的区间。现在问题变成了:给定若干个区间,告诉 x 在不在区间内,让你求 x

对于“在”区间内的情况,直接全部取交集即可。对于“不在”的情况,先按左端点排序,这样会方便考虑,然后逐一合并相交的区间,再取补集,最后与“在”的区间合并即可。

注意判断无法找到的情况、有多个的情况还有没有“不在”区间的情况。


E. A Simple Task

Link-CF
Link-Luogu

【难度分析】

思维难度:D+
实现难度:B
总体难度:C+
评级: 提高+/省选-

【题目大意】

给定一个长度为 n 的,仅由小写字母组成的字符串 S,有 m 次操作,对于每次操作:

  • SlSr 升序排序。
  • SlSr 降序排序。

求最终的字符串。

  • 1n1051m5×104

【解题思路】

定义函数 f(x),表示在字母表中排名为 x 的字母;g(c) 表示字母 c 在字母表中的排名。

由于只有 26 种字符,考虑对每种字符都建立一颗线段树,这样我们需要 26 颗线段树。

具体的,第 i 颗线段树维护字母 f(i) 的位置(和区间内的出现次数)。这样,根据线段树的叶子节点存储的信息可以计算每个位置的字符。

考虑排序操作,这里只讨论升序排序,因为降序排序同理即可。

我们观察一个例子:对于 acababc 进行排序,结果是 aaabbcc。这里,第 11+31 位置是 a,第 44+21 位置是 b,第 6 到第 6+21 位置是 c。注意到这里的 422 是这些字符在区间内的个数。于是我们就有了一种方案:

每次修改时,从小往大枚举字符,这样就可以保证升序。对于字符 i,我们将第 g(i) 颗线段树 p+1p+cnt+1 修改为 1,其他修改为 0。其中,p 为上一个字符的末尾,cnt 为这个字符在修改的区间内的出个数。这样就可以完成的排序的操作了。

这里,我们利用了两个性质:排序后相同的字符是连续的;排序操作不影响区间内字符的个数。

输出的时候,我们遍历时遍历到叶子节点输出即可。

时间复杂度 O(26 mlog(n))

其实此题与这个题有着较为相似的思路,只不过后者将值域从 26 扩大为正整数,需要二分答案,略难一些,有余力的读者可以尝试一下。

posted @   Eliauk_FP  阅读(62)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示