Runs 学习笔记
unputdownable · · 题解
本文以文字说明为主,记号较少,可能存在一些非正式表述,请谅解。
前置知识:字符串哈希或后缀数组,脑子。
记
记
称一个字符串的
如果没有讨论越界问题,默认
首先,什么是 runs?
一个字符串 aabcabcabb 中 abcabcab 这个子串就是一个 runs。
一个 runs 必然存在最小周期,记最小周期长度为
- 长度至少为
2p ,即周期至少出现两遍; - 不能向两侧扩展,即
s_{r+1} \neq s_{r+1-p} ;对于左侧同理。
所以,对于串 aabcabcabb 而言,子串 abcab 和 abcabca 都不能算作 runs。
接下来讨论如何去求所有 runs。
如果现在已经找到了某个 runs 的某个最小周期
任意一个在 runs 范围中且长度为
记上述操作为一次检查。要想找出所有 runs,只需要检查所有可能的周期即可。
任何一个 runs 都有
从其中最小的串入手,假设这是
这玩意其实可以叫最小表示法,一般的求法是重复原串两遍,取
但是由于这是 runs,可以证明这还是一个 Lyndon Word,即所有后缀都比原串大,以下是简要证明:
首先说明对于任意非空串
a,b ,(a+b)^k+a (k \in \Z^+ ) 一定不是一个最小表示法,考虑a+(a+b)^k 与(b+a)^k+a 这两个串就能推出矛盾。反证法,不妨假设我们找到的串是
r 有一个后缀s 比原串小。因为任何循环同构都大于等于r ,可以推出s 是r 的前缀,即s 是r 的一个\text{border} 。首先
|s| 不能是|r| 的因数,否则|r| 就不是最小周期;若
|s|<\frac{|r|}2 ,则r 可以写成s+t+s ,必然不是最小表示法;若
|s|>\frac{|r|}2 , 记r=s+t ,则s 必然有周期t ,取t 长度为|s| \bmod |t| 的前缀为a ,记剩下的为b ,则s=(a+b)^k+a ,r=(a+b)^{k+1}+a ,也必然不是最小表示法。
所以对于任意
那么
同时可以发现
所以,通过找到所有
对于
不存在
这也就是 runs 数量小于等于
最后,如果这个 runs 包含
讨论一些实现细节。
第一种实现是使用后缀排序。需要写正串和反串两遍 SA。通过写 SA-IS 加上四毛子可以做到线性求 runs。
第二种是直接字符串哈希,使用二分哈希/倍增哈希
代码就不放了,哈希应该不至于不会写吧,记得去重。
后记:其实并不是初学 runs,纯粹是昨晚和同学口胡 runs 后几天心血来潮写了一篇。