题解 AT4379 【[AGC027E] ABBreviate】
题意简述
给定一个只含小写字母
- 选取
s 中连续的两个字符\mathtt{aa} ,把它们删去,替换成一个字符\mathtt{b} 。 - 选取
s 中连续的两个字符\mathtt{bb} ,把它们删去,替换成一个字符\mathtt{a} 。
请你求出执行若干次操作后,能够得到的本质不同的字符串有多少个,答案对
题解
我们考虑判断一个字符串
假设可以,则对于
也就是,
这里有个很有趣的结论:如果我们把
也就是说,定义
那么回到变成字符的问题上来,如何判断
显然
但是这并不是充分条件,考虑
如果
考虑归纳:当
也就是说,字符串
那么再回到一开始的问题:字符串
很自然地,有一个贪心匹配的算法:
依次考虑
举个例子,当
最后
特别地,这个最后一段需要满足
我们可以证明:
注意:证明部分可以酌情跳过!
注意:证明部分可以酌情跳过!
注意这里包含了两个条件,第一个是成功分段,第二个是
我们先考虑
那么在后续证明中假定
我们首先证明它的必要性,即任意一个合法的
- 对于某个
t ,我们考虑它在s 中对应的每个段。 - 即
s = s_1 \, s_2 \, \cdots \, s_{|t|} ,这里每个s_i 都是一个字符串,且s_i 变成了t 的第i 个字符。 - 假设
t_i 对应的s_i 是第一个非最短前缀(也就是说之前的字符对应的前缀都是最短的)。 - 令此时的最短前缀为
x ,则s_i = x \, y ,其中p(y) = 0 。 - 因为
p(y) = 0 ,考虑把y 并入后一个s_{i + 1} ,以保证s_i 的最短性。 - 如果
s_{i + 1} 不存在,也就是i = |t| ,则结论自然成立(y 成为最后一段未匹配后缀)。 - 否则当前的
s_{i + 1} \gets y \, s_{i + 1} ,此时至少需要保证s_{i + 1} 是合法的,如果合法就可以继续递归。 - 但是问题在于可能不合法,可以发现此时
|s_{i + 1}| \ge 2 ,那么就是s_{i + 1} 中不存在相邻的相同字符。 - 也就是形如
y = \mathtt{baba} ,而原先的s_{i + 1} = \mathtt{b} 的这种形式,新的s_{i + 1} = \mathtt{babab} 。 - 那么我们注意到,如果把
s_{i + 1} 拆分为\mathtt{b|abab} 两段,然后把\mathtt{abab} 继续并入后面进行讨论。 - 这样就可以保证此时的
s_{i + 1} = \mathtt{b} ,显然是最短的,然后把问题转移到后面了,递归即可。 - 所以我们证明了:任意一个合法的
t 都能够成功分段。
还需要证明它的充分性,即只要能够成功分段,那就一定是合法的:
- 考虑最终分段的情况,假如不存在最后一段未匹配后缀,则自然成立,否则:
- 假设
s = s_1 \, s_2 \, \cdots \, s_{|t|} \, s_{|t| + 1} ,其中s_{|t| + 1} 是未匹配后缀,我们要想办法把这个后缀塞到前面去。 - 首先直接把
s_{|t|} 与s_{|t| + 1} 合并,如果可行就合法,不过如果不可行呢? - 类似地,自然有形如
s_{|t|} = \mathtt{a} 和s_{|t| + 1} = \mathtt{baba} 这种形式。 - 那么我们令
s_{|t|} = \mathtt{a} ,然后把\mathtt{abab} 往前转移。 - 因为有「
s 中存在相邻的相同字符」这个条件,这个过程一定会因为合并出了相邻的相同字符而停止。 - 所以我们证明了:任意一个能够成功分段的
t 都是合法的。
证明部分结束。
证明部分结束。
那么我们先特判
令
则答案就是
我代码中实现的时候,为了方便,把
时间复杂度为