字符串杂记
关于 Z 函数
这东西不能说和 Manacher 一模一样,只能说两模两样。
都是充分的利用 \(Z\) 最大的那个的信息,继承过来拓展。
在 Manacher 里面是 \(P[2C - i]\),这里是 \(Z[i - l + 1]\)。然后就随便暴力就行了。
关于 border
神秘的性质……他们是怎么想到的?
P5287 给到的技术是 KMP 自动机,利用可持久化线段树做到 \(O(n \log |\Sigma|)\) 的复杂度不均贪的完成 KMP 的匹配过程。考虑 KMP 的过程,实际上是跳 fail
树上第一个具有 c
出边的点,观察到每次只会修改一个点,可持久化就简单了。对于本题来说正是利用这个过程,只是稍微抽象了一点,因为一次加了多个相同的字符,那么可持久化就需要一个 tuple
。转移的时候增加的是一个等差数列,继承答案转移即可。
然而对于 JOJO 这道题来说,还有一种与 border
性质更相关的做法。注意到 period
可以被划分为 \(O(\log n)\) 个等差数列,实际上 fail
树也可以被划分为若干的等差数列,并且,\(x\) 到根的链上也只有 \(O(\log n)\) 次变换,那么如果据此链剖分,那么就可以做到 \(O(n \log n)\) 的复杂度,与 \(|\Sigma|\) 没有关系了。然而我实际是不会写的。
关于 SAM
- 在 SAM 上 \(lcp(i, j)\) 就是 \(i, j\) 对应点在
parent
树上 \(\mathrm{lca}\) 的 \(\mathrm{len}\)。P4248 - 可以利用倍增找到某个子串的出现次数。P3649
- 串的匹配,放在
SAM
节点上转移即可,如果没有就跳link
,注意更新长度 P6640。本题中还需要狠狠注意匹配的单调性,设 \(len_i\) 表示从 \(i\) 开始最长的公共串长,虽然 \(len_i\) 不满足单调性,但是 \(i + len_i\) 是满足的,考虑不可能存在包含的情况。于是就是一个简单的二分和 RMQ 问题。 - 出现与非出现的问题,CF427D,考虑出现一次的串,那么在
SAM
上的体现就是为叶子,对应的长度就是只出现一次的长度。两个串都要满足的话就需要建立两个SAM
,一个作为模板,一个提前记录位置即可。 - 两个自动机内的问题 P4608 善用记忆化即可。
关于 SEQAM
仍然注意可以利用可持久化线段树完成 \(O(n \log n)\) 构建。
1295C - Obtain The String 超简单。
关于广义 SAM
两种写法。
- 离线将所有串建出
Trie
,然后在其上bfs
,正常的插入SAM
即可。 - 在线,还是正常的
SAM
,但是特判,参考 题解 的代码。大概就是将有ch[p][c]
的情况特判出来,其他都是一样的。
关于字典序的比较
最简单也最万能的就是二分哈希找第一个不同,直接判断即可。
序列最小表示法也可以用这个方法比较做到 \(O(n \log n)\)。