字符串技术巡礼
字符串技术巡礼
前言
本文主要内容是一些许多人不怎么会的字符串组合算法,而主要内容基本可以理解为论文导读。笔者认为,许多技术是可以被放入(甚至可以说很适合被放入)OI 的框架中的,只是由于这些技术引入 OI 的时机较晚,因此尚未得到普及。
1. 记号与约定
字符集是一个全序集,默认是有限的,记为
字符串是由若干字符(字符集的元素)构成的序列,字符串的集合记为
-
字符串
w 的长度定义为包含的字符数量,记为|w| 。 -
若
|w|=0 ,则定义w 为空串,记为\varepsilon ,空串是唯一的。 -
记
\Sigma^+=\Sigma^* - \{\varepsilon\} 。 -
记
w_i 表示w 的第i 个字符。 -
记
w[l,r] 或w[l\ldots r] 表示由w_l,\ldots,w_r 组成的字符串,称为w 的一个子串。当l>r 时定义w[l,r]=\varepsilon 。 -
称
w[1,i] 为w 的一个前缀,w[i,n] 为w 的一个后缀。 -
若
w 的一个子串(前缀/后缀)不等于w ,则称其为真子串(真前缀/真后缀)。 -
若
u 是v 的前缀,记作u\sqsubseteq v ;若u 是v 的真前缀,记作u\sqsubset v 。 -
对于两个串
u,v ,u+v 或uv 定义为一个长度为|u|+|v| 的串w ,其中w_i=u_i\ (i\leq |u|),\ w_i=v_{i-|u|}\ (i>|u|) ,称为u,v 的拼接。 -
定义
\operatorname{Rev}(u) 为一个长度为|u| 的串v ,其中v_i=u_{|u|-i+1} 。 -
若
w=\operatorname{Rev}(w) ,则称w 为回文串。 -
定义
\operatorname{LCP}(u,v) 表示最大的i 使得i\leq \min(|u|,|v|) 且u[1,i]=v[1,i] 。 -
定义
\operatorname{LCS}(u,v) 表示最大的i 使得i\leq \min(|u|,|v|) 且u[|u|-i+1,|u|]=v[|v|-i+1,|v|] 。 -
对于两个串
u,v ,我们称u 的字典序比v 小,或u<v ,当且仅当以下条件满足至少一个:-
-
存在一个
1\leq i\leq \min(|u|,|v|) 使得u[1,i-1]=v[1,i-1],\ u_i<v_i ,将这种情况记为u\lhd v 。
-
2. 前置知识
并非在每种技术中都会用到全部的前置知识,但这些是字符串理论的基础,几乎都在 NOI 大纲内。
字典树
不再赘述。
自动机
不再赘述。
我们通常考虑有限状态自动机,其中分为确定性有限状态自动机和非确定性有限状态自动机。字典树也可以看作一个自动机。
Border 和周期
对于字符串
若整数
结论:
定理(周期引理,Periodicity Lemma):若
弱周期引理(Weak Periodicity Lemma,WPL)是一个弱化版本,即将上述条件替换为
结论:
我们可以
Aho-Corasick 自动机
对于一个字符串集合
对于树上结点
令:
其中
以
当
结论:设串
结论:
我们可以
后缀数组
定义排列
定义排列
对于
结论:
我们可以
后缀树
设
将字典树上所有度数为
如果只缩那些不对应
也有一种说法是在
类似我们在 AC 自动机中所做的,可以求出失配数组
结论:后缀树结点数为
后缀自动机
能接收
记
结论:后缀自动机状态数和转移数为
结论:后缀自动机的每个结点代表一族
结论:
我们可以
回文树 / 回文自动机
将
对于一个回文串
结论:回文串的所有 Border 都是回文串,回文子串
我们可以
Manacher 算法
我们可以
Z 函数
我们可以
3. 区间 Border / 基本子串字典
论文:陈孙立,子串周期查询问题的相关算法及其应用,IOI 2019 集训队论文集
基本子串字典被引入 OI 可能主要是为了解决区间 Border 问题,即:
- 给定一个字符串
w ,有q 次询问,每次给定一个w 的子串w[l,r] ,求它的 Border 集合。
根据 Border 的相关知识,我们知道
- 定义:考虑
w 的所有长度为2^k 的子串w[i,i+2^k-1] ,给予它们标号N_k(i) 使得N_k(i)\leq N_k(j) \iff w[i,i+2^k-1]\leq w[j,j+2^k-1] ,且N_k(i) (关于i )的值域是连续的正整数。对于所有k ,这一系列标号数组N_k 称为w 的基本子串字典。
对于任意字符串
-
引理 1:对于字符串
u,w ,如果2\times |u|\ge |w| ,则u 在w 中作为子串出现时的左端点构成了一个等差数列。 -
证明:如果
u 在w 中的出现次数不超过2 ,则结论显然。下面考虑u 出现至少三次的情形。 考虑任意三次相邻的u 的出现,设其左端点分别是l,l+p_1,l+p_1+p_2 ,由2|u|\ge |w| 可知p_1+p_2\leq |u| ,那么因为p_1,p_2 都是u 的周期,所以根据 WPL 可知p_0=\gcd(p_1,p_2) 也是u 的周期。考虑这三次出现的并,即
w[l,l+p_1+p_2+|u|-1] ,由p_0 是u 的周期不难得到p_0 是w[l,l+p_1+p_2+|u|-1] 的周期,从而l+p_0 或l+p_1+p_0 也是合法的(即u 出现的)左端点,而这与p_1\ne p_2 的假设矛盾(其中至少一个不等于p_0 ),因此原命题得证。
设
- 推论:在上述引理的条件下,如果
u 在w 中出现至少三次,则这些出现的左端点构成的等差数列公差等于u 的最小周期。
让我们回到需要求解的问题:求出
考虑
根据引理 1,
-
引理 2:如果
|S_1|>2 且|S_2|>2 ,则它们的公差相等。 -
证明:根据上一个引理及其推论,可知此时
S_1 的公差等于u_0 的最小周期p_u ,S_2 的公差等于v_0 的最小周期p_v ,假设p_u\ne p_v 。以
p_u>p_v 为例,p_u<p_v 的情况是类似的。考虑u_0 在v 中最靠右的一次出现,设其与v_0 部分的交为y 。一方面y 是v_0 的前缀,从而有周期p_v ,另一方面根据u_0 在v 中的出现可知p_u 也是y 的周期,且|y|\ge 2\times p_u>p_u+p_v ,从而p=\gcd(p_u,p_v) 也是y 的周期。这说明
p 也是u_0[|u_0|-p_u+1,|u_0|] 的周期,从而是u_0 的周期,这与p_u 的最小性矛盾。
于是如果我们已知
这就要用到基本子串字典。以
将序列以
于是,我们
基本子串字典还有一些其他应用,例如:
-
问题:给定字符串
w ,q 次询问其中两个子串是否相等。若两个子串分别是
w[a,a+l-1] 和w[b,b+l-1] ,找到最大的k 使得2^k\leq l ,则两个子串相等等价于N_k(a)=N_k(b) 且N_k(a+l-2^k)=N_k(b+l-2^k) 。 预处理O(|w|\log |w|) ,查询O(1) 。 -
树上扩展
基本字串字典的概念可以直接扩展到树上,只不过将“以
x 为左端点长度为2^k 的子串”换成“x 到其2^k 级祖先路径上边的字符拼接得到的串”,这可以由倍增算法的一种树上改造O(|T|\log |T|) 求出,其中|T| 为树的结点数。
论文中还提到了一种基于基本字串字典的求
-
例题:[Luogu P8006] String Rearrangement in Phantom
-
题目大意:给定字符串
w ,q 次询问,每次给定l_1,r_1,l_2,r_2 ,求有多少个字符串三元组(A,B,C) ,使得w[l_1,r_1]=A+B+C,\ w[l_2,r_2]=C+\operatorname{Rev}(B)+A 。|w|\leq 2\times 10^5,\ q\leq 10^5 -
题解:
A,C 分别可以表示成O(\log |w|) 个等差数列,枚举一对等差数列,然后考虑A,C 分别在这两个等差数列中的方案数。设这两个等差数列分别对应的可能的
A,C 为A_1,\ldots,A_k ,C_1,\ldots,C_l ,长度递减排列。那么A_1,\ldots,A_k 中相邻两项的差应该是个定值(A_1 的长度等于最小周期的后缀),记为u ,同理C_1,\ldots,C_l ,这个差值记为v 。如果
|A_1|+|C_1|\leq len (len 是给定子串的长度),那么它们的出现无交,我们只需要检查两个子串各删掉对应A_1,C_1 的部分后是否互反,以及u,v 是否互反(即A_1 的长度为|u| 的前缀和后缀是否互反,v 同理)即可确定答案。但是如果
|A_1|+|C_1|>len ,那么上面的做法就会失效。此时,如果|A_3|+|C_1|\leq len 或者|A_1|+|C_3|\leq len ,那么我们可以特判A_1,A_2 或C_1,C_2 然后应用上面的方法。否则,根据引理 2(有一些细微的不同,但整体是类似的),可以知道A_1,\ldots,A_k 和C_1,\ldots,C_l 公差相同,设为d 。此时,中间一整段(从
A_k 结尾到C_l 开头,所有与B 的选取有关的位置)都有周期d ,我们任取一组总长最长的不相交的A_i,C_j ,如果中间的部分互反,则所有A_{i+k},C_{j-k} 也是可行的,因为中间的部分都一样。此时如果A_i,C_{j+1} 也满足中间的部分互反,说明加入一个周期不会对B 的合法性产生影响,因此这时任何一对不相交的A,C 都是合法的。时间复杂度
O(|w|\log |w|+q\log^2|w|) 。
4. 对称压缩 SAM / 基本子串结构
论文:徐翊轩,浅谈压缩后缀自动机,IOI 2020 集训队论文集
论文:许庭强,一类基础子串数据结构,IOI 2023 集训队论文集
基本子串结构和基本子串字典基本上是完全没有关系的两个东西。
在前置知识中我们介绍了后缀自动机。后缀自动机是接收
后缀自动机的特点是每个结点代表的是一系列字符串,且它们都是其中最长者的后缀,这或许可以作为名称的由来(尽管本身可能不是这么来的)。我们换一个视角来看,SAM 是一个“向左扩展”的自动机,因为任意给定一个子串
于是我们想:有没有向右扩展的自动机呢?当然这就是反串的 SAM。那么有没有向两侧扩展的自动机呢?
- 定义:考虑串
w 。对于任意一个w 的子串u ,定义\operatorname{occ}(u) 为u 在w 中的出现次数。\operatorname{Lext}(u) 为最长的以u 为后缀的串u' ,使得u' 和u 在w 中的\operatorname{occ} 相同;\operatorname{Rext}(u),\operatorname{Ext}(u) 类似,只不过定义中u 分别是u' 的前缀和子串。
首先要说明
那么现在我们想建立一种结构,使得
我们从 SAM 出发构建这一结构,SAM 已经完成了向左扩展,只需再实现向右扩展即可。对于 SAM 上的一个结点
- 定义:将
w 的 SAM 上出度为1 且不代表后缀的结点与其出边指向的结点合并,得到的自动机称为w 的压缩后缀自动机。
注意,上面的论文中将这个东西称为“完整压缩后缀自动机”,相应地本文中的后缀树在论文中被称为“完整后缀树”,而论文中相应的“压缩后缀自动机”和“后缀树”对应的是本文中的隐式压缩后缀自动机(即把所有出度为
下图展示了
压缩 SAM 虽然是一个两侧扩展的自动机,但是它的转移边仍然是单向的——沿着转移边只能从前往后加字符。不过注意到反串 SAM 也可以压缩,并且得到的压缩 SAM 和正串压缩 SAM 应该是结点一一对应的(因为每个结点都是一个
- 定义:将
w 的正反 SAM 分别压缩,对应结点叠合,同时保留两个自动机上的转移,得到的结构称为w 的对称压缩后缀自动机。
对称压缩 SAM 上有两种不同类的转移,一种是向后加字符,另一种是向前加字符。因此,对称压缩 SAM 相比普通 SAM 在处理字符串问题上的优势就体现为:能够解决同时需要往左右两边加字符的问题。
对称压缩 SAM 刻画了不同的
我们将
下图展示了
以同种颜色边框围成的区域就是一个块,本质不同的块与压缩 SAM 上的结点一一对应。而压缩 SAM 上的边即可看成横向或纵向(分别对应反串压缩 SAM 和正串压缩 SAM)相邻的两块之间的转移,这种转移关系在上图也画出来了。
根据对压缩 SAM 的讨论,我们可以得到如下结论:
-
结论 1:每个块是一个上端和左端对齐的阶梯形网格图,即存在
l_a,l_b,r 使得这一块中的所有格子恰为\{(x,y)\mid l_a\leq x\leq l_b,\ f(l_a)\leq y\leq r\} ,其中f 单调不降。 -
证明:首先我们说明一个块是上端和左端对齐的,即上边界和左边界不会是凹的,即如果存在两个子串
w[l_1,r_1] 和w[l_2,r_2] 属于同一块,则w[\min(l_1,l_2),\max(r_1,r_2)] 也属于这一块。这很容易说明,只要考虑\operatorname{Ext} 即可,这些串的\operatorname{Ext} 都是相同的。再说明它确实是阶梯型网格图。现在我们已经知道块有一个左上顶点,即所有块中串的
\operatorname{Ext} ,记这个极长的串为w[l,r] 。我们只需说明如果\operatorname{Ext}(w[l',r'])=w[l,r]\ ([l',r']\subset [l,r]) 则\operatorname{Ext}(w[l'-1,r'])=w[l,r]\ (l'>l) 和\operatorname{Ext}(w[l',r'+1])=w[l,r]\ (r'<r) 即可,这由\operatorname{Ext} 的定义可以直接得到。
于是,对于一个块
-
结论 2:每个串出现且只出现在一种块中,且在块中只出现了一次,每种本质不同的块
C 恰好出现了\operatorname{occ}(\operatorname{Rep}(C)) 次。 -
证明:每个串显然只能出现在一种块中,因为其
\operatorname{Ext} 是唯一的。\operatorname{Rep}(C) 在C 中只出现了一次,而它在整个串中出现了\operatorname{occ}(\operatorname{Rep}(C)) 次,所以C 就出现了\operatorname{occ}(\operatorname{Rep}(C)) 次,而C 中的其他串也出现了\operatorname{occ}(\operatorname{Rep}(C)) 次,所以它们不可能在C 中出现两次或以上(否则总次数就不对了)。
对于一个块
-
结论 3:一块中的一行对应一个
\operatorname{Endpos} 等价类,从而对应一个 SAM 结点;一列对应一个\operatorname{Startpos} 等价类,从而对应一个反串 SAM 结点。 -
证明:以结论前半部分为例。根据 SAM 部分中讲过的内容,一个
\operatorname{Endpos} 等价类一定是网格图上某一行的一个连续段。一块中的一行\operatorname{Endpos} 一定相同,且如果往两边扩展则\operatorname{occ} 都不同,\operatorname{Endpos} 肯定不会相同,所以又不能扩展,从而就是一个\operatorname{Endpos} 等价类。 -
结论 4:
\sum_C h(C)+w(C)=O(|w|) ,其中求和是对本质不同的块求和。 -
证明:由结论 3,每个 SAM 结点会为
\sum_C h(C) 贡献1 ,每个反串 SAM 结点会为\sum_C w(C) 贡献1 ,由 SAM 结点数的结论知\sum_C h(C)+w(C)=O(|w|) 。
有了结论 3,我们还可以进一步研究 SAM 上的后缀链接对应到基本子串结构上的结果。根据上面的对应,SAM 上的后缀链接就发生在横向相邻的两块的交界处,反串 SAM 上的后缀链接就发生在纵向相邻的两块的交界处。
结论 4 是很多算法复杂度的保证。例如,如果在每一块上有一个
之前我们介绍了用基本子串字典处理区间 Border 的方法,而基本子串结构给了另一种看待区间 Border 问题的视角。
子串
这(给块选位置)对于后续的算法并不是必要的,但它能直观地告诉我们一些性质,所以下面我们递归地给出一种构造,以正串 SAM 的链接树为例:从叶子出发,叶子的出现次数当然都是
下图展示了
对于正串 SAM 链接树上一条重链,令其编号为其叶结点所在的行;对于反串,则是叶结点所在列。
-
结论 5:同一个块中,所有正(反)串 SAM 结点对应的正(反)串 SAM 链接树上重链编号连续。
-
证明:因为在一条重链上,所以每个结点与其重链上的叶子在同一行(列),根据编号的定义知道是连续的。
下面我们回到区间 Border 问题,现在问题已经转化为寻找两棵树上两个祖先链的交,我们先把祖先链转化为
考虑每个正串 SAM 上的点,它对应的是基本子串结构某个块的一行,于是其中所有串就属于这一块中的不同的列,根据结论 5,这些列对应的反串 SAM 结点所在重链编号连续,所以每个正串 SAM 结点对应的是一个反串 SAM 重链编号的区间,而我们要查询的就是正串 SAM 某条重链上有多少个点对应的区间包含某个给定的反串重链。
但是注意我们考虑的并不是一整条重链,而只是重链的一个前缀(靠近根的部分),这可以通过加上一维长度来限制,即我们所求的是正串 SAM 一条重链和反串 SAM 一条重链的交集中长度
以区间 Border 计数为例,对于每条正串 SAM 重链,它对应的数据结构问题可以描述为:给定二维平面中若干个斜率为
-
例题:[SDOI / SXOI 2022] 子串统计
-
题目大意:给定一个字符串
w ,令T_0=w ,T_i 是在T_{i-1} 的基础上删除第一个或最后一个字符得到的串,最后T_{n-1} 是一个只包含一个字符的串。总共有2^{n-1} 种删除方案(尽管得到的T 序列可能有一些是相同的),每种方案的权值定义为\prod_{i=0}^{n-1}\operatorname{occ}(T_i) ,求所有方案的权值和对998244353 取模。|w|\leq 10^5 -
题解:每种方案可以看成是一条在基本子串结构上从左上角走到反对角线
x=y 上任何一个点的只能往右或往下走的路径,我们要对所有路径上的点权乘积求和,由于权值用\operatorname{occ} 定义,所以同一块内所有点的权值相同。不妨把路径反过来,变成从对角线上的任何一个点走回到左上角。我们单独考虑一块,如果路径经过这一块,那么一定是从这一块的右下轮廓上某个点出发,走到左上边界的某个点,而这部分的贡献是可以用一个经典的分治 NTT 算出,所以只要(按照从右下到左上的顺序)对每一块都算一遍贡献即可,相邻块之间的贡献可以在边界处(即正反 SAM 后缀链接)转移。
对某一块
C 算的复杂度是O((h(C)+w(C))\log^2(h(C)+w(C))) ,所以总复杂度O(|w|\log^2 |w|) 。 -
例题:[数据删除]
稍后公布。
5. Lyndon 分解 / Significant Suffix
论文:万成章,浅谈与 Lyndon 理论有关的字符串组合问题,IOI 2022 集训队论文集
Lyndon 理论是用来解决与字典序相关的问题的一套理论,不过在代数上它似乎有别的用处,但这和本文无关。
- 定义:如果一个串
w 满足它小于它的所有非空真后缀,即\forall i\in [2,|w|],\ w<w[i,|w|] ,则称w 是一个 Lyndon 串。
由于
再介绍一个和 Lyndon 串有关的概念。对于字符串
- 定义:如果一个串
w 满足存在一个 Lyndon 串u 使得w=u^ku' ,其中u' 是u 的真前缀,则称w 是一个近似 Lyndon 串。
对于字符串
我们下面证明,一个串
-
引理 1:若
u,v 都是 Lyndon 串且u<v ,则uv 是 Lyndon 串。 -
证明:如果
u\sqsubset v 则由v 是 Lyndon 串知uv<v ;如果u\lhd v 则显然uv<v 。故无论如何uv<v 。对于
v 的非空后缀v' ,有uv<v\leq v' ,对于u 的非空真后缀u' ,有u\lhd u'\to uv\lhd u'v ,因此uv 小于它的所有非空真后缀,即uv 是 Lyndon 串。 -
引理 2:若
w=w_1+\ldots +w_k 是w 的 Lyndon 分解,则w 的最小非空真后缀为w_k 。 -
证明:设
w 的最小非空真后缀为u=u'w_i\ldots w_k ,其中u' 是w_{i-1} 的非空后缀,则u\ge u'\ge w_{i-1}\ge w_k ,而w_k 是一个后缀,所以u 只能等于w_k 。
根据引理 1 可以说明 Lyndon 分解的存在性:初始时令每个字符都是一个 Lyndon 因子,然后不断合并相邻的满足
根据引理 2 可以说明 Lyndon 分解的唯一性:最后一个 Lyndon 因子总是最小非空真后缀,删掉它后递归即可。至此我们成功证明了 Lyndon 分解是唯一存在的。
我们可以将 Lyndon 分解中相邻相同的 Lyndon 因子写在一起,成为
-
Duval 算法:
O(|w|) 地求出w 的 Lyndon 分解。从前往后依次加入
w 的每个字符,一边加一边分解。设当前加入到字符w[i] ,我们维护当前前缀一个还没有被分解的后缀w[j,i] ,我们时刻保证这个后缀是一个近似 Lyndon 串,对应的 Lyndon 串长度为k ,即设u=w[j,j+k-1] ,u 是一个 Lyndon 串且w[j,i]=u^tu' ,u' 是u 的真前缀。现在我们加入字符w[i+1] :-
若
w[i+1]=w[i+1-k] ,则自然延续近似 Lyndon 串即可; -
若
w[i+1]>w[i+1-k] ,则此时w[j,i+1] 本身是一个 Lyndon 串了,所以我们令k\leftarrow i-j+2 。 -
若
w[i+1]<w[i+1-k] ,则w[j,i+1] 不再是一个近似 Lyndon 串,我们将w[j,j+k-1],w[j+k,j+2k-1],\ldots 这些 Lyndon 串分解出来(它们是相等的),作为w 的 Lyndon 因子,直到j+pk-1\ge i+1 。令新的j 为j+(p-1)k ,然后将i 回滚至j ,k\leftarrow 1 ,重新加入一遍w[j],\ldots,w[i] 这些字符,加入过程同上。
若所有字符都加入完毕了,则类似上面最后一种情况,把当前近似 Lyndon 串
w[j,|w|] 的 Lyndon 前缀w[j,j+k-1],w[j+k,j+2k-1],\ldots 分解出来,然后将i 回滚到最后余下一段的开头再加一遍。 -
Duval 算法的正确性可以直接验证——它分解出的每个子串确实都是 Lyndon 串,且字典序确实递减。
Duval 算法的复杂度不难证明。每当分解出一段 Lyndon 因子
- 定义:如果
w 的一个后缀w' 满足:存在一个v 使得对于w 的任何后缀w'' 都有w'v\leq w''v ,则称w' 是w 的一个 Significant Suffix。w 的所有 Significant Suffix 的集合记为\operatorname{SS}(w) 。
Significant Suffix 有一个性质:如果
一些与字典序相关的问题可以归于对 Significant Suffix 的讨论,所以我们首先介绍其一些性质。
-
引理 3:如果
v,uv,u^2v\ (u\neq \varepsilon) 都是w 的后缀,则uv\notin \operatorname{SS}(w) 。 -
证明:事实上我们有
uvy<vy\iff u^2vy<uvy ,所以uvy 总不是最小的。
设
-
引理 4:
w 的 Significant Suffix 一定形如w_i^{p_i}\ldots w_k^{p_k} ,将这个串记为s_i 。 -
证明:第一步说明 Significant Suffix 形如
w_i^t\ldots w_k^{p_k} 。考虑形如uw_i^t\ldots w_k^{p_k} 的后缀,其中u 是w_i 的真后缀,则w_i\lhd u ,故w_i^{t+1}\ldots w_k^{p_k}\lhd uw_i^t\ldots w_k^{p_k} ,这说明了以u 开头的这个后缀不是 Significant Suffix。第二步说明上述形式中一定有
t=p_i ,若0<t\ne p_i ,则考虑w_i^{t-1}\ldots w_k^{p_k},\ w_i^t\ldots w_k^{p_k},\ w_i^{t+1}\ldots w_k^{p_k} 这三个后缀,形成了引理 3 中v,uv,u^2v 的形式,于是其中的w_i^t\ldots w_k^{p_k} 就不是 Significant Suffix。
设
现在考虑
-
引理 5:
s_{i+1}\sqsubset s_i\iff s_{i+1}\sqsubset w_i\iff i\ge \lambda ,其中s_\lambda 为 Duval 算法第一次比较完w 的末尾时的近似 Lyndon 串。 -
证明:如果
i<\lambda ,说明 Duval 算法过程中某一时刻近似 Lyndon 串为w_i^{p_i}w' 且下一个字符为c ,其中w' 是w_i 的真前缀,c>w_i[|w'|+1] ,这说明w_i\lhd s_{i+1} ,从而s_{i+1}\not\sqsubset s_i,\ s_{i+1}\not\sqsubset w_i 。如果
i=\lambda ,则s_i 是近似 Lyndon 串,同时根据 Duval 算法的规则可知s_{i+1}\sqsubset w_i ,于是s_{i+1}\sqsubset s_i ,同时 Lyndon 串的前缀一定是近似 Lyndon 串,所以s_{i+1} 也是近似 Lyndon 串,于是对于i>\lambda 的情况可以归纳。
于是我们说明了 Significant Suffix 只会在
- 结论 1:
|\operatorname{SS}(w)|=O(\log |w|) ,且较长的 Significant Suffix 长度大于较短的 Significant Suffix 的长度的两倍。
现在让我们回答一个基本的问题:给定
-
引理 6:
uv<v\iff u^{\infty}<v -
证明:设
v=u^tu's ,其中u' 是u 的真前缀,s=\varepsilon 或s[1]\ne u[|u'|+1] 。若s=\varepsilon ,则v\sqsubset uv 且v\sqsubset u^{\infty} ;若s[1]>u[|u'|+1] ,则uv\lhd v 且u^{\infty}\lhd v ;若s[1]<u[|u'|+1] ,则v\lhd uv 且v\lhd u^{\infty} 。无论如何,结论都成立。
对于
-
引理 7:
x_i^{\infty}>x_{i+1}^{\infty} 。 -
证明:显然
x_i^{\infty}>y_i ,只需证明y_i>x_{i+1}^{\infty} 即可。在两边前面都加上一个s_{i+1} ,等价于要证s_{i+1}y_i>s_{i+1}x_{i+1}^{\infty} ,而s_{i+1}y_i=w_i,\ s_{i+1}x_{i+1}^{\infty}=w_{i+1}^{\infty} ,由w_i 是 Lyndon 串以及w_{i+1}\sqsubset w_i 知w_i>w_{i+1}w_i (考虑删去一个公共前缀w_{i+1} ),于是由引理 6 知w_i>w_{i+1}^{\infty} ,至此命题得证。
因此只要我们找到一个
- 结论
2 :\operatorname{SS}(w)=\{s_\lambda,\ldots,s_k\} ,且:\operatorname{Minsuf}(w,v)=\begin{cases}s_\lambda v & v>x_\lambda^{\infty} \\ s_iv & x_{i-1}^{\infty}>v>x_i^{\infty} \\ v & x_k^{\infty}>v\end{cases} 。
许多字典序相关问题都可以转化为求
-
例题:[ZJOI 2017] 字符串
-
题目大意:维护一个长度为
n 的字符串(数字序列)w ,支持q 次操作:区间加,求区间最小后缀。n\leq 2\times 10^5,\ q\leq 30000 -
题解:既然有区间加这样的操作,自然尝试用线段树维护
w 。不过现在关键的问题是我们无法直接从左右两边的最小后缀合并得到它们拼接后的最小后缀,不过如果我们维护了两边的所有 Significant Suffix,就可以进行合并了。如果我们已知
\operatorname{SS}(u) 和\operatorname{SS}(v) ,并且|v|\ge |u| ,那么根据上面的结论 1,\operatorname{SS}(u) 中只有至多一个能够被选进\operatorname{SS}(uv) ,唯一的候选者自然就是\operatorname{Minsuf}(u,v) 。由于多算一些串进\operatorname{SS}(uv) 其实并没有关系(只要数量仍然是O(\log |uv|) 就行),所以我们就将\operatorname{SS}(v)\cup \{\operatorname{Minsuf}(u,v)\} 看作\operatorname{SS}(uv) 。从而我们可以在线段树上维护每个点对应子串的 Significant Suffix 集合(尽管可能多算一些串),如果查询两个子串大小关系的复杂度为O(\log n) 的话,一次 pushup 的复杂度就是O(\log^2 n) 。查询时,只需要找到所有拆分出的线段树上的结点的所有 Significant Suffix 并选一个最小的即可,复杂度为
O(\log^3 n) 。考虑如何实现
O(\log n) 比较两个子串大小关系。可以以修改的时间代价换查询的时间代价,采用分块,维护每个点到块末尾的哈希值和块端点到末尾的哈希值,即可O(\sqrt n) 修改,O(1) 求出子串哈希值,从而套一个二分就能O(\log n) 查询子串 LCP 和比较子串大小。复杂度为
O(n\log^2 n+q(\log^3 n+\sqrt n)) ,如果用线段树替代分块则为O(n\log^2 n+q\log^4 n) 。 -
例题:[数据删除]
稍后公布。
-
例题:[数据删除]
稍后公布。
6. 幂串 / Runs
7. 杂技
-
广义 SAM
-
SAM 上的 DAG 剖分
-
回文串
-
Lyndon 计数问题