runs 知识点

本文以文字说明为主,记号较少,可能存在一些非正式表述,请谅解。

前置知识:字符串哈希或后缀数组,脑子


记 sisi​ 为字符串 ss 的第 ii 个字符(11 下标),默认字符串的长度是 nn。

记 sl,rsl,r​ 为从 ll 到 rr 的字符组成的子串。

称一个字符串的 ii 后缀为从第 ii 个字符开始的后缀,ii 前缀则是到第 ii 个字符终止的前缀。

如果没有讨论越界问题,默认 s0=sn+1=−inf⁡s0​=sn+1​=−inf,即小于任意字符。


首先,什么是 runs?

一个字符串 ss 中的一个 runs 是一个循环子串,例如 aabcabcabb 中 abcabcab 这个子串就是一个 runs。

一个 runs 必然存在最小周期,记最小周期长度为 pp,对应子串是 sl,rsl,r​,则一个 runs 还要满足:

  • 长度至少为 2p2p,即周期至少出现两遍;
  • 不能向两侧扩展,即 sr+1≠sr+1−psr+1​=sr+1−p​;对于左侧同理。

所以,对于串 aabcabcabb 而言,子串 abcab 和 abcabca 都不能算作 runs。


接下来讨论如何去求所有 runs。

如果现在已经找到了某个 runs 的某个最小周期 si,jsi,j​,那么可以通过对 ii 后缀和 j+1j+1 后缀求一次最长公共前缀来向右扩展,以及对 i−1i−1 前缀和 jj 前缀求最长公共后缀来向左扩展,最后检查是否满足 runs 的条件就能找到这个 runs。

任意一个在 runs 范围中且长度为 pp 的子串其实都能被称为 "周期",下文直接称其为周期。

记上述操作为一次检查。要想找出所有 runs,只需要检查所有可能的周期即可。


任何一个 runs 都有 pp 种周期,他们互为循环同构的串,仍然假设这个 runs 是 sl,rsl,r​。

从其中最小的串入手,假设这是 si,jsi,j​(因为长度至少是 2p2p 所以这样的串必然存在)。

这玩意其实可以叫最小表示法,一般的求法是重复原串两遍,取 1∼n1∼n 后缀中最小的后缀再截取 nn 前缀就行。

但是由于这是 runs,可以证明这还是一个 Lyndon Word,即所有后缀都比原串大,以下是简要证明:

不妨假设我们找到的串是 rr 有一个后缀 ss 比原串小。因为任何循环同构都比 rr 大,可以推出 ss 是 rr 的前缀,又因为 rr 是最短周期,所以 rr 必然没有大于等于原串长度一半的 border,则令 r=s+t+sr=s+t+s

由 rr 是所有循环同构中最小的,可得 s+t+s≤s+s+ts+t+s≤s+s+t,s+t+s≤t+s+ss+t+s≤t+s+s 从而推得矛盾。

所以对于任意 i+1≤k≤ji+1≤k≤j,kk 后缀要大于 ii 后缀。

那么 j+1j+1 后缀是 ii 后面第一个可能比 ii 后缀小的后缀。

同时可以发现 j+1j+1 后缀与 ii 后缀的大小关系取决于 sr+1sr+1​ 与 sr+1−psr+1−p​ 的大小关系(就是之前取最长公共前缀的两个后缀)。

所以,通过找到所有 ii 后缀后面第一个比他小的后缀,并且检查对应区间,可以找出所有 sr+1<sr+1−psr+1​<sr+1−p​ 的 runs。

对于 sr+1<sr+1−psr+1​<sr+1−p​ 的 runs,从最大的周期(即反转字符大小关系下的最小,注意此时空字符应当大于所有字符)入手即可。即找到所有 ii 后缀后面第一个比他大的后缀,就可以找出所有这一类 runs。

不存在 sr+1=sr+1−psr+1​=sr+1−p​ 的情况,所以,通过检查至多 2n2n 次,可以找出所有 runs。

这也就是 runs 数量小于等于 2n2n 的证明。

最后,如果这个 runs 包含 kk 个完整周期,那么最小/大周期也会出现至少 k−1k−1 次,所以记得去重。


讨论一些实现细节。

第一种实现是使用后缀排序。需要写正串和反串两遍 SA。通过写 SA-IS 加上四毛子可以做到线性求 runs。

第二种是直接字符串哈希,使用二分哈希/倍增哈希 O(log⁡n)O(logn) 求最长公共前后缀以及后缀比较。使用单调栈就只需要 O(n)O(n) 次比较,总复杂度也是 O(nlog⁡n)O(nlogn)。

代码就不放了,哈希应该不至于不会写吧,记得去重。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值