后缀数组

排名\(i,j,k\) 的后缀( \(i<k<j\)),满足\(Lcp(i, j) = min(Lcp(i, k), Lcp(k, j))\)

用这个可以递推得到
性质1排名\(i\)的后缀与排名\(j\)的后缀的最长公共前缀为$min_{k = i}^{j - 1} \ h(k) $
性质2 :设 \(rk(i)\)表示后缀\(i\)的排名,则有\(h(rk(i))\ge h(rk(i - 1)) - 1\)

\(h(rk(i))\) 表示 \(s[i - 1 :|s|]\)\(s[sa(rk(i) + 1) : |s|]\) 的最长公共前缀
\(h(rk(i - 1))\) 表示 \(s[i:|s|]\)\(s[sa(rk(i - 1) + 1) : |s|]\)
去掉\(s[i - 1:|s|]\)\(s[sa(rk(i - 1) + 1) : |s|]\)的第一个字符,就是
\(s[i :|s|]\)\(s[sa(rk(i - 1) + 1) + 1 : |s|]\) , 他们的\(lcp \ge h(rk(i - 1)) - 1\)(去掉一个字符最多让最长公共前缀长度-1),而有因为相邻排名的后缀是最相似的,也就是\(h(rk(i))\ge lcp(后缀i, 任意后缀)\) 所以 \(h(rk(i)) \ge h(rk(i - 1)) - 1\)

不同子串个数

任何一个子串都可以表示成一个后缀的前缀
总子串个数是 \(\frac{n * (n + 1)}{2}\),有重复的
重复的个数是 \(\sum_{i = 2}^{|s|}h(i)\),因为重复的只会由字典需排名最接近的相同前缀产生,产生了最长公共前缀个数个重复的子串,而非相邻排名却重复的在减的时候也覆盖了
或者可以理解为最终的不同子串个数是$$\frac{|s|(|s| + 1)}{2} - \sum_{i = 2}^{|s|}h(i)$$
理解为按照字典需的顺序依次插入后缀,产生等同于后缀长度减去\(h(i)\)个新的子串

生成魔咒

发现正着加入后缀字符时,原来的所有后缀长度+1,而且新增一个后缀,不好做
可以把字符串倒置,然后就变成了往最前端新增一个后缀(不同子串个数不变)
于是离散化之后,去一次\(sa\),\(height\),然后加字符的过程,当前的\(height\)的和,动态维护
就是在插入的时候用这个字符串的排名(前面统一算了一遍,不用加一个算一次),找到它当前的前驱,后继(排名在他前面和后面的两个,set维护) 然后利用性质1可以区间求最小值,查找出这个字符串与前驱和后继分别重复的
字符串个数,减去,然后发现减重了在把前驱后继的重复部分加回来(重复的个数,就是两个字符串的最长公共前缀,已height为元素,用st表维护最小值,更具性质1快速求出)

差异

\[\sum_{1\leq i < j \leq n} len(T_i) + len(T_j) - 2 * lcp(T_i,T_j) \]

\[= \frac{(n - 1) n (n + 1)}{2} - 2 \; \; *\sum_{1\leq i < j \leq n}lcp(T_i,T_j) \]

由性质1,后面一坨

\[\sum_{1\leq i < j \leq n}lcp(T_i,T_j) = \sum_{1\leq i < j \leq n}\min_{i+1\leq k \leq j}h(k) \]

找相同字符

把两个串拼在一起得到A,两个选出的相同子串个数为

\[\sum_{u \in S} \sum_{v \in T} lcp(u, v) \]

(在拼的时候两个字符串中间插入特殊字符,就不会出现公共前缀也跨串的情况,这个式子就相当与在两个串各选一个后缀,lcp对的和)

发现这个跨串的lcp对和不好求,可以转换成所有lcp对数和减去处于同一个串内

\[\sum_{1 \leq i < j \leq |A|} lcp(A[i:], A[j:]) - \sum_{1 \leq i < j \leq |s|} lcp(s[i:],s[j:]) - \sum_{1 \leq i < j \leq |t|}lcp(t[i:],t[j:]) \]

和差异一样
还有另一种求lcp对的方法,枚举右端点,覆盖左端点,也是用单调栈好求

posted @ 2026-02-26 08:42  wmq2012  阅读(5)  评论(0)    收藏  举报