后缀数组与马拉车学习笔记
后缀数组与马拉车学习笔记
串串这种细节特别多的比较弱啊,加练加练。
这篇学了 UKE 的标题编号方法看看会不会让观感更好
1 后缀数组
1.1 定义
后缀和子串这些基本定义就不放了吧(
- 
排名:字典序排名,空位补 \(0\)(注意这个 \(0\) 是 ASCll 的 \(0\) 而非字符 \(\text 0\))。 
- 
后缀的下标:后缀的起始位置的下标。 
- 
\(sa_i\):所有后缀中排名为 \(i\) 的后缀的下标。 
- 
\(rk_i\):下标为 \(i\) 的后缀在所有后缀中的排名。 
- 
\(\text{lcp}(i,j)\):下标为 \(sa_i\) 与 \(sa_j\) 的后缀的最长公共前缀的长度。 
- 
\(h(i)\):\(\text{lcp}(i,i-1)\) 

1.2 实现
我们先考虑如何求 \(sa\) 和 \(rk\)。
首先有一个显然的性质:\(sa_{rk_i}=rk_{sa_i}=i\),这个实在是太显然了,我们考虑先求 \(sa\),然后用这个性质求 \(rk\)。
我们发现对于两个长度为 \(2n\) 的字符串 \(s,t\),\(s>t\) 可以转化为 \(s[1,n]>t[1,n]\) 或 \(s[1,n]=t[1,n]\) 且 \(s[n+1,2n]>t[n+1,2n]\)。
我们注意到这就是一个经典的二元组排序,只要将 \([1,n]\) 设为第一关键字,\([n+1,2n]\) 设为第二关键字排序后即可得到排名,而这两个关键字本身也可以分治求解,注意到这个东西的复杂度显然是 \(\log n\) 的,套上 sort 的 \(n\log n\) 就能 \(n\log^2n\) 解决,但是现在这个东西常数大而且本身复杂度劣,考虑优化。
我们现在的瓶颈显然是 sort,考虑将其换成基数排序,这里默认大家都会了,显然可以省去一个 \(\log\)。
代码细节有点\(\huge 多\),但是我懒得贴代码了,读者加油吧(?)
然后是 \(h\) 和 \(\text{lcp}\)。
对于 \(h\),有这样一个性质:
\(h_{rk_i}\ge h_{rk_{i-1}}-1\)。
证明:
当 \(h_{rk_{i-1}}\le1\) 时,上式显然成立。
否则因为 \(h_{rk_{i-1}}=\text {lcp}(sa_{rk_{i-1}},sa_{rk_{i-1}-1})\),注意到这里的 \(sa_{rk_{i-1}}=i-1\),我们设这里的 \(\text {lcp}\) 为 \(\text{aA}\)(小写字母为字符,大写字母为字符串或空),后缀 \(i-1\) 为 \(\text{aAD}\),后缀 \(sa_{rk_{i-1}-1}\) 为 \(\text{aAB}\)。
也就是说后缀 \(i\) 是 \(\text{AD}\),后缀 \(sa_{rk_{i-1}-1}+1\) 为 \(\text{AB}\)。
而又因为 \(sa_{rk_{i}-1}\) 的排名只比 \(i(sa_{rk_{i}})\) 低一位,又有 \(\text{AB}<\text{AD}\),所以有 \(\text{AB}\le sa_{rk_{i}-1}< \text{AD}\) 也就是说 \(i\) 与 \(sa_{rk_{i}-1}\) 有共同的前缀 \(\text A\)。
于是 \(h_{rk_{i}}=\text{lcp}(sa_{rk_{i}},sa_{rk_{i}-1})=\text{lcp}(i,sa_{rk_{i}-1})\ge |A|=h_{rk_{i-1}}-1\),得证。
对于 \(\text{lcp}\),有以下几个性质:
- 
\(\text{lcp}(i,j)=\text{lcp}(j,i)\)(显然) 
- 
\(\text{lcp}(i,i)=n-sa[i]+1\)(定义得) 
- 
\(\text{lcp}(i,j)=\min(\text{lcp}(i,k),\text{lcp}(k,j))(i\le k\le j)\) 这个得证一下: 设 \(\text {lcp}(i,j)=q\),\(\min(\text{lcp}(i,k),\text{lcp}(k,j))=p\)。 - 
首先如果你是人类应该能看出 \(q\ge p\)。 
- 
接下来当 \(q>p\) 时显然有 \(q\ge p+1\),也就是说下标为 \(sa_i\) 的后缀和下标为 \(sa_j\) 的后缀中前 \(p+1\) 个字符都一样。 但是因为 \(p\) 是 \(\min(\text{lcp}(i,k),\text{lcp}(k,j))\),所以下标为 \(sa_k\) 的后缀的第 \(p+1\) 位至少和它们两个中一个的第 \(p+1\) 位不一样。 而因为 \(i\le k\le j\),所以如果下标为 \(sa_j\) 和下标为 \(sa_i\) 的后缀的第 \(p+1\) 位一样而和下标为 \(sa_k\) 的后缀的第 \(p+1\) 位不一样那么它们两个的字典序中显然就不会夹着个 \(k\) 了,所以它们两个的第 \(p+1\) 位不一样,得出 \(q\le p\),从而有 \(q=p\)。 
 
- 
- 
\(\text{lcp}(i,j)=\min(h_k)\forall k\in i<k\le j\)(由上一条易扩展得) 
1.3 例题
1.3.1 [JSOI2007] 字符加密
题目大意
原题晰。
题解
考虑把这个β循环断开,倍长字符串后跑板子即可。
1.3.2 [洛谷P2408] 不同子串个数
题目大意
原题晰。
题解
考虑正难则反,计算相同子串的数量后减去 \(\sum_{i=1}^nh_i\) 即可
1.3.3 [ural1297] Virtual Judge
题目大意
求一个字符串的最长回文子串。
题解
这个题怪显然的,把这个字符串倒着拼在它本身后面之后跑板子,然后这样匹配:

细节有点多,记得分类讨论奇数和偶数长度,中间还要有一个分界符比如 # 之类的。
1.3.4 [POI 2000] 公共串
题目大意
原题晰。
题解
先把所有串都拼到一起,然后考虑求出 \(h\) 后问题转化为找连续的一段使得至少每个串都出现一次,用一个长得很像莫队的双指针维护即可。
1.3.5 [USACO06DEC] Milk Patterns G
题目大意
求一个字符串中至少出现了 \(K\) 次的子串的最长长度。
题解
注意到以这种子串开头的后缀肯定是相邻的,所以问题转化为对于所有长度为 \(K-1\) 的子序列中 \(h\) 的最小值最大是多少,那单调队列或者随便啥数据结构瞎维护即可。
1.3.6 [SDOI2008] Sandy 的卡片
题目大意
公共串,但是如果一个串整体加或减后能匹配也算匹配。
题解
差分后跑 1.3.4 即可。(诶这个编号还真有用)
1.3.5 [SCOI2012] 喵星球上的点名
题目大意
原题晰。
题解
\(h\) 数组预处理后考虑按 \(sa\) 排序后预处理出能匹配到的姓/名,然后莫队瞎搞即可。
1.3.6 [AHOI2013] 差异
题目大意
原题晰。
题解
考虑求出所有 \(\text{lcp}\) 后用总长度 \(n\times(n+1)\times(n-1)\) 减,这就是一个显然的单调栈问题了。
1.3.7 [bzoj3230] 相似子串
题目大意
原题晰。
题解
细节\(\small{\huge\text巨}\)多的一道题啊。
自己手膜时也能发现的一个性质是一个后缀的前缀的排名是连续的,然后就这样去编号就可以了,接着二分找合法区间即可。
1.3.8 [NOI2015] 品酒大会
题目大意
原题晰。
题解
对 \(h\) 降序排序后一个插入,用并查集维护这个过程即可。
2 manacher
用于求解回文问题及其变种。
2.1 实现
我们首先规定对于一个回文串,它的中心就是 \(\lfloor\frac{l+r+1}{2}\rfloor\) (即偶数长度回文串中心是中间靠右)
接着设 \(d\) 为以 \(i\) 作为中心的奇数长度回文串的个数,只记录奇数的原因是这样处理而且对于一个字符串 \(\text{abacbab}\) 可以将其改为 \(\text{\#a\#b\#a\#c\#b\#a\#b\#}\),之后以 \(\text{\#}\) 为中心的回文串对应到原串上就是偶数长度的了。
我们动态维护最靠右的回文串,如果当前点在这个回文串内就可以直接从它的对应点开始扩展,否则就是它自己暴力扩展。
注意点最靠右回文串的右端点是不降的,所以复杂度线性。
2.2 例题
2.2.1 [POI 2010] ANT-Antisymmetry
题目大意
原题晰。
题解
把判断回文的条件改为不等即可。
2.2.2 神奇项链
题目大意
求最少用多少个回文子串可以完全覆盖原串。
题解
考虑贪心,维护 \(r_i\) 表示中心最右的能包含 \(i\) 的回文子串的中心,然后不断这样跳就行了。
2.2.3 [国家集训队] 拉拉队排练
题目大意
原题晰。
题解
把 \(d\) 搞到桶里,然后做后缀和用快速幂更新答案即可。
2.2.4 [ZJOI2009] 对称的正方形
题目大意
找到有多少个上下对称且左右对称的正方形。
题解
上下左右分别处理,用 ST 表维护能拓展长度的最小值,二分出最大的合法长度,统计答案时对上下拓展长和左右拓展长取 \(\min\) 即可。
 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号