Loading

字符串大乱炖

本文是 cmd 的《字符串选讲》的速通版。

最小后缀

记号

  • \(suf(s)\) 是字符串 \(s\) 的后缀集合。
  • \(minsuf(s)\) 是字符串 \(s\) 的最小后缀。
  • \(Ssuf(s)\) 是字符串 \(s\) 的未来可能最小后缀,对于 \(t\in Ssuf(s)\),存在一个字符串 \(r\),使得 \(tr=minsuf(sr)\)

性质

性质 \(1\): 对于 \(u,v\in Ssuf(s)\),若 \(|u| < |v|\),那么 \(u\)\(v\) 的前缀。

很显然吧,反证法很容易证。

性质 \(2\):对于 \(u,v\in Ssuf(s)\),若 \(|u|<|v|\),那么 \(2|u| \le |v|\)

考虑反证法,假设 \(2|u| > |v|\)

由于性质 \(1\),那么 \(u\)\(v\) 的 Border,那么 \(v\) 的周期 \(|v| - |u|\) 小于 \(|v|\)。设 \(a\)\(v\) 长度为 \(|v|-|u|\) 的前缀,\(v=aab\),\(u=ab\)

如果 \(u=minsuf(sr)\),那么 \(ur<vr\implies abr<aabr\implies br < abr \implies br<ur\),与假设相反,所以 \(u\) 不可能是属于 \(Ssuf(s)\)

即得证。

性质 \(3\)\(Ssuf(s)\) 的大小为 \(O(\log |s|)\)

从性质 \(2\) 得证。

题目

P5211

每次修改用 \(O(\sqrt n)\) 更改信息,使查询字串哈希值为 \(O(1)\)

考虑使用线段树维护 \(Ssuf(s)\)。每个节点维护当前区间的 \(Ssuf\),考虑合并子树信息,由于性质 \(2\),那么 \(ls\)\(Ssuf\) 只保留一个,从小到大逐个比较即可,设目前最优的是 \(p\),要加入 \(t\)

  • \(pR\)\(tR\) 的前缀,因为性质 \(2\),留下 \(t\)
  • 否则留下字典序更小的。

再通过类似的方法得到 \(Ssuf(LR)\)。复杂度 \(O(n\log^2 n+m\log^3+m\sqrt n)\)

P5334

也类似不写了。

Runs

定义

三元组 \(r=(l,r,p)\) 是字符串 \(s\)\(run\)。那么 \(s[l,r]\) 的最小周期是 \(p\),并且 \(r-l+1\ge 2p\)\(s_{r+1} \not =s_{r+1-p}\)\(s_{l-1} \not = s_{l-1+p}\)

\(e_r=\frac{r-l+1}{p}\) 是该 \(run\) 的指数。

\(Runs(s)\)\(s\) 的所有 \(run\) 集合。

性质

性质 \(1\)\(|Runs(s)| < |s|\)\(\sum_{r\in Runs(s)} e_r \le 3n - 3\)

proof is so hard。不写了。

性质 \(2\):两个周期为 \(p\)\(run\) 的交小于 \(p\)

很明显吧,如果交大于等于 \(p\),就可以合并成一个 \(run\)

求 Runs

枚举 \(p\)。在字符串中每 \(p\) 个点中放一个关键点。那么一个 \(run\) 合法一定要经过两个相邻的关键点,枚举每个相邻的关键点用后缀排序得出它们的 \(LCP/LCS\),如果覆盖可以连接那么构成一个 \(run\)。由于性质 \(2\),得出一个 \(run\) 之后可以跳过一些关键点不访问。

当然也是会算重,比如 \(r=(l,r,p)\),可能会多算 \(r=(l,r,kp)\),后面取最小的即可,复杂度 \(O(n\log n)\)

本原平方串

定义

一个字符串 \(s\) 是本原平方串当且仅当它的最小周期为 \(\frac{|s|}{2}\)

性质

性质 \(1\):若 \(ss\)\(tt\) 的前缀,且 \(2|s| > |t|\),可知 \(|t|-|s|\)\(s\) 的周期。

画个图就知道了。

性质 \(2\):若 \(uu\)\(vv\) 的前缀,\(vv\)\(ww\) 的前缀,且 \(uu\) 是本原平方串,那么 \(|u|+|v|\le |w|\)

proof is so long。不写了。

性质 \(3\):字符串 \(s\) 的本原平方串的数量为 \(O(|s|\log |s|)\)

由性质 \(2\) 可得,因为以每个点为开始的本原平方串最多有 \(O(\log |s|)\) 个,类似斐波那契数列。

性质 \(4\):字符串 \(s\) 中本质不同的本原平方串个数为 \(O(|s|)\) 个。

考虑性质 \(2\) 中的 \(uu,vv,ww\),其中 \(2|uu| \le |w|\),那么 \(uu\) 会被计算多次,所以暂不统计,即每个点开始的只会贡献 \(2\) 个。

求出本原平方串

先求出 Runs,很明显一个本原平方串一定在一个和其周期相等的 run 中。一个 run 中所有长度为 \(2p\) 的子串都是本原平方串,由性质 \(2\) 可知,\(\sum_{r\in Runs(s)} r-l+2-2p\)\(O(|s|\log |s|)\)

题目

uoj429

考虑 \(O(n^2)\) 的 DP,发现它是根据 run 转移的,并且一个 run 的转移代表一个等差数列,一个等差数列直接继承之前即可,转移次数 \(\sum_{r\in Runs(s)} r-l+2-2p\),即复杂度为 \(O(n\log n)\)

P6629

直接刻画所有本原平方串,去重直接差分即可。

posted @ 2025-02-11 15:27  larsr  阅读(12)  评论(0)    收藏  举报