ABC325EF 题解

D - Ulam-Warburton Automaton

想清楚了其实很简单,但有些细节处理上的问题,赛时容易搞不明白。

下文用 \(n\)\(m\) 表示题目中的 \(H\)\(W\),且两者视为同级。

最暴力的想法是,每轮更新时暴力枚举所有的节点,判断它在这一轮是否被涂黑。如果某一轮没有节点被涂黑,则结束程序。这样每轮的时间复杂度为 \(O(n^2)\),而轮数容易构造到 \(O(n)\)(一开始只有一个角为黑色),所以总时间复杂度为 \(O(n^3)\),无法通过。

称在第 \(k\) 轮被涂黑的点为\(k\) - 新增点。在第 \((k + 1)\) 轮更新时,只需判断与 \(k\) - 新增点相邻的点是否能被涂黑即可。这是显然的:在第 \((k + 1)\) 轮一个点从不能被涂黑变为能被涂黑,说明其相邻节点中恰有一个点在上一轮被涂黑,所以它必然与 \(k\) - 新增点相邻。

由于每个点最多被涂黑一次,而一个点被涂黑时只会检测相邻 \(4\) 个点能否被更新,所以每个点都只会被检测 \(O(1)\) 次,因此总时间复杂度为 \(O(n^2)\),可以通过。

总结一下流程:

  1. 初始化队列 \(f\)\(g\) 为空。把初始就被涂黑的节点视为 \(0\) - 新增点,加入队列 \(f\) 中。
  2. \(f\) 中所有点涂黑。
  3. \(f\) 中每个点,检测与其相邻的点是否能涂黑。如果能,把此相邻的点加入 \(g\) 中。
  4. 如果 \(g\) 为空,说明不存在新的被涂黑的点,结束程序。否则,令 \(f \gets g\) 并清空 \(g\),回到第 2 步。

参考代码

E - Count Sequences 2

多重集排列数板子,典得不能再典的问题,这都能放来当比赛题的?

\(n = \sum C_i\),通常使用的公式为

\[ans = \dfrac{n!}{\prod_{i = 1}^{N} C_{i}!} \]

但是模数不是质数,不一定存在乘法逆元,所以不能使用带除法的式子。使用另一个公式就好了:

\[ans = \dbinom{n}{C_1}\dbinom{n - C_1}{C_2} \cdots \dbinom{n - C_1 - C_2 - \cdots - C_{N - 1}}{C_N} \]

用杨辉三角递推式可以在 \(O(n^2)\) 时间内预处理组合数,且不需要除法,于是就做完了。

参考代码

(但是赛时忘了第二个公式,想了半天)

F - Inserting Process

看到 \(N\) 很小,容易想到把每个子序列设为一个状态,这样状态数为 \(2^{N}\)。正着加字符是困难的,因为我们难以快速判定,一个子序列插入一个字符得到的字符串是不是原串的子序列。套路性地倒着考虑,即研究有多少种方法可以把原串删为空串。

一个简单的想法是:用下标序列 \((1, 2, \cdots, n)\) 的子序列 \((p_1, p_2, \cdots, p_m)\) 表示子序列 \(t = s_{p_1}s_{p_2}\cdots s_{p_m}\),枚举删去的字符来转移。问题在于:一个字符串删去不同位置的字符,可能得到相同的字符串,例如 \(\tt{aab}\) 删去第一个字符或第二个字符得到的字符串都是 \(\tt{ab}\),这样就算多了。

于是我们要解决的问题是:如何使子序列的表示方式唯一?例如对于 \(s = \tt{aab}\),我们希望子序列 \(t = \tt{ab}\) 只有一种表示方式。实际上,在转移的过程中,简单地加上一条限制即可:如果出现连续相同的字符,只能删除最右边的字符。那么,\(\tt{aab}\) 只能删除第二个字符得到 \(\tt{ab}\),这样两个子序列之间的转移就唯一了,因而解决了算重的问题。

另外多说一句,我们确实给每个子序列找到了唯一的表示方式:如果一个子序列的表示方式不唯一,我们总是取字典序最小的那个。例如 \(\tt{ab}\)\(\tt{aab}\) 中的表示方式有两个:\((1, 3)\)\((2, 3)\),而我们只会转移到字典序较小的 \((1, 3)\)。这不难感性理解,严谨证明可能需要使用一下数学归纳法,但我们最好不要陷入抽象的形式化语言中。

总结:对于有重复贡献的问题,考虑给每个对象确定一个唯一的表示方式。这种思想是相当常见的。

参考代码


UPD on 10/4: 新增了 D 的题解。

posted @ 2025-09-27 22:45  DengStar  阅读(38)  评论(0)    收藏  举报