[CodeForces] CF558 题解

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

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

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


A. Lala Land and Apple Trees

Link-CF
Link-Luogu

【难度分析】

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

【题目大意】

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

  • \(1 \leq n \leq 100\)\(-10^5 \leq x_i \leq 10^5\)\(x_i \neq 0\)\(1 \leq a_i \leq 10^5\)

【解题思路】

考虑贪心。

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


B. Amr and The Large Array

Link-CF
Link-Luogu

【难度分析】

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

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

【题目大意】

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

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

形式化地,有

\[f(A) = \max_{1 \leq i \leq n}(\sum_{j = 1}^{n}[A_i = A_j]) \]

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

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

  • \(1 \leq n \leq 10 ^ 5\)\(1 \leq a_i \leq 10 ^ 6\)

【解题思路】

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


C. Amr and Chemistry

Link-CF
Link-Luogu

【难度分析】

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

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

【题目大意】

\(n\) 个数,第 \(i\) 个数为 \(a_i\),你可以对每个数进行一下操作:

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

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

  • \(1 \leq n \leq 10 ^ 5\)\(1 \leq a_i \leq 10 ^ 5\)

【解题思路】

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

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

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

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

\[f_v = f_u + n - 2 * g_v \]

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

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

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

注意 \(a_i\) 可重复。注意根节点的 \(f\) 的初始值。


D. Guess Your Way Out! II

Link-CF
Link-Luogu

【难度分析】

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

【题目大意】

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

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

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

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

  • \(1 \leq h \leq 50\)\(1 \leq q \leq 10 ^ 5\),保证信息合法。

【解题思路】

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

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

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

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


E. A Simple Task

Link-CF
Link-Luogu

【难度分析】

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

【题目大意】

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

  • \(S_l \sim S_r\) 升序排序。
  • \(S_l \sim S_r\) 降序排序。

求最终的字符串。

  • \(1 \leq n \leq 10 ^ 5\)\(1 \leq m \leq 5 \times 10 ^ 4\)

【解题思路】

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

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

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

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

我们观察一个例子:对于 acababc 进行排序,结果是 aaabbcc。这里,第 \(1\)\(1 + 3 - 1\) 位置是 a,第 \(4\)\(4 + 2 - 1\) 位置是 b,第 \(6\) 到第 \(6 + 2 - 1\) 位置是 c。注意到这里的 \(4\)\(2\)\(2\) 是这些字符在区间内的个数。于是我们就有了一种方案:

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

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

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

时间复杂度 \(O(26\) \(m \log(n))\)

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

posted @ 2024-11-20 10:36  Eliauk_FP  阅读(16)  评论(0编辑  收藏  举报