数学杂谈 #14
Period and Border
简明的定义
-
字符集:表示字符串中所有可能出现的字符的集合,通常用 表示。
一般来说,我们遇到的字符集为小写字符集 。
-
字符串:字符串的集合可以用如下定义:
这个集合中的元素的直观理解就是我们通常所知的字符串——由若干个(可以为零个)字符集内的字符顺序构成的......一串东西。
通常我们习惯用 表示在当前字符集下的一个字符串。
-
字符串的长度:对于字符串 ,我们通常就用 表示它的长度,也就是所含字符个数。
-
字符串的拼接:对于字符串 ,我们可以用 表示将 的字符按照顺序添加入 的末尾后得到的字符串。
-
子串:对于字符串 ,我们习惯于对于它的字符写成一行,然后从左往右按顺序编号为 。
如是我们可以用 表示编号为 的字符。
接着我们可以定义子串,用 表示 拼接而成的字符串,且需要满足 。特别地,在某些情况下,我们会认为 代表了 为空串,即不包含任何字符的字符串。
较为特殊的子串是前缀和后缀。我们会用 表示 ,用 表示 。自然需要满足 ,但当 的时候,我们一般会认为 和 返回空串。
-
字符串的幂:如果我们将字符串的拼接看作是“乘法”操作,那么相应地,我们可以定义“幂”:用 表示 个 的拼接结果。
的情况不多说。特别地, 可以是一个有理数。不妨设 ,则 表示 。这个定义带来了限制,也就是 。
-
字符串的比较:对于字符串 ,如果 且 ,我们就说 。
Period
字符串可以看作是数列,数列可以看作是特殊的函数,因此字符串的周期也和函数的周期非常类似。这些东西有必然联系吗?
对于字符串 ,如果有整数 ,且满足 ,则称 为 的一个周期。
一般来说,我们主要在讨论最小正周期,因此我们可以用 表示字符串 的最小的周期。
一种等价的理解是,如果 是 的周期,那么 就应该是 的前缀,或者 。
Weak Periodicity Lemma
这个叫做弱周期引理,至于为什么“弱”,待会儿你就知道了。内容如下:
对于一个字符串 ,如果有 都是 的周期,并且 ,则可以得出 也是 的周期。
这个东西挺好理解的,也挺好证明的:
对于 进行归纳证明。
首先,我们不妨假设 。边界的情况就是 ,此时 ,显然成立。
接着,考虑 的情况。假设该定理对于任意的 都已被证明,其中 或 成立。
由于 ,则对于 ,有 或 其一成立。
前者可以推出 ,而后者可以推出 。总而言之,我们得到了 也是 的一个周期。
由于 ,根据归纳假设可以知道 也是 的一个周期,所以 也是 的一个周期。
说白了,不就是辗转相除的过程吗。
Periodicity Lemma
这就是正版的周期引理。至于为什么不“弱”,你待会儿就知道了。内容如下:
对于一个字符串 ,如果有 都是 的周期,并且 ,则可以得出 也是 的周期。
证明看起来非常复杂,这里就感性理解一下吧。
Border
直译过来应该叫做字符串的“边界”,不过我着实没有看见过任何一个人这样称呼它的。
不过,从词语的含义入手,这个定义其实还是相当易于理解的:
对于一个字符串 ,如果存在整数 ,且满足 ,那么就称 为 的一个 Border。
在下文你有可能看见,我们会用 表示 的所有 Border 构成的集合。
Border and Period
我们在这里将要讨论 Border 和 Period 的对偶性。说白了就是,周期和 Border 存在一一对应的关系。
- 从周期到 Border 时,我们选一个周期 。根据定义,,换言之就是 ;
- 而从 Border 到周期时,我们选某个 Border ,且令 ,则由 可以得到 。
这一点很重要,因为我们马上就可以看到它的应用。
Structure of Border
从字符串本身来看,我们不难得出:Border 的 Border 还是 Border。
假设有字符串 ,且 。
取 ,再取 。
根据定义有 ,因此 。
我决定称上述命题为 BBaB 命题,来源于 Border's Border is still a Border。
一个更加重要的论断是:
取出 ,那么 。
我们平时写 KMP 找 Border,其实就基于上述论断。
如果上述命题为伪,那么我们可以取出 ,且 。
由于 的性质,我们可以知道 。类似于 BBaB 的证明方式,我们可以说明 应当 ,矛盾。
这个论断告诉我们,我们可以用树来描述每一个前缀的 ,这样每个结点的 就是树根到该节点的路径上,所有结点对应的字符串的集合。
从数值上看,我们先需要两个引理。
引理之一:
对于字符串 ,它的所有长度 的 Border 的长度可以构成一个等差数列。
特别提醒:我们这里将 本身也看作是它的一个 Border,也即 Border 的长度取值范围为 。
证明就需要将 Border 的问题转化到周期上面来:
设 。如果有 ,那么就没什么可说的了。
否则,取另外一个周期 。如果不存在这样的 ,那也没什么可说的。
否则,根据 Weak Lemma,我们可以知道 也是一个周期,结合 的性质我们可以知道 。
因此有 。由于 的任意性,我们可以知道 都是周期,并且给出的相邻两项之间不存在任何别的周期。
将周期对应到 Border 上,我们就得到了引理。额外的修正来自于 本身,我们只需要将 0 加入到首位即可。
接着是引理之二:
对于字符串 ,如果 ,我们则定义 。
此外的定义是 。
那么有: 中的元素可以构成一个等差数列。
这个引理其实就是引理之一的推广,因为上面一个引理讨论的就是 的情况。
因此,证明可以直接顺着这个思路来:
不妨假设 ,取出 。
此时对于任意的 ,都有 ,这一步仍然无比类似于 BBaB 的论证方式。
因此,我们可以得到 。由于 ,我们即可结合引理之一得到证明。
以下是最终的推论:
对于任何一个字符串 ,它的所有 Border 可以按照长度被划分为 个等差数列。
我们先设 。构造方法有两种:
-
递归构造。先取出 ,然后构造出一个等差数列。
构造结束后剩下长度 的 Border,直接递归进入 构造。
每次长度折半,因此最终会得到 个等差数列。
-
直接按照长度划分。我们暂时不考虑长度为 0 的 Border。
这样我们可以将 划分为 ,其中 是整数且满足 。
对于其中的一个区间,我们将会说明长度落在该区间内的 Border 可以构成等差数列。
- 对于区间 ,我们知道 ,因此可以构成等差数列。
- 对于区间 ,我们面对的就是 ,还是可以构成等差数列。
KMP
我们在此定义 表示 ,显然应当满足 。
KMP 最核心的部分就是求出指定字符串 中每个 的 ,之后的字符串匹配不过就是一个应用。
这是一个增量的算法,也就是我们可以在 后加入一个字符 而回答 的 。当然,由于 仅仅和前缀相关,我们只需要求出 就好了。
这个算法的关键就在于,我们要知道 ,这个不难理解或证明。因此,在我们求 的时候,我们只需要按照长度从大到小枚举 中的元素,检查能不能往后塞一个 。根据 的结构,我们可以直接跳 链完成按顺序枚举这个过程。
KMP 的复杂度是均摊 的,此处略过。不过,由于 KMP 还是一个增量算法,因此我们可以动态地向字符串后面“插入”字符而保证复杂度正确这不废话么。但是如果存在删去字符的情况,那分析就失效了——也就是 KMP 不能回退。
Period's' of a Substring
这个部分看起来不是很简单,而且我的 Typora 已经开始卡了,要不先停一停。
Examples
用本文的语言来描述一下这个题:给定字符串 ,进行 次询问。每次询问给出 ,求 。
用树来表示 的结构,这就不难发现询问求的就是 和 在树上的 LCA。
于是,按照这道题的本意,我们已经“完美地”解决了问题,复杂度为 。
不过,我们既然已经知道了数值上 Border 的等差结构,我们就可以用好这个信息来简化流程。
说简单一点,我们直接按照等差数列来划分树链,并模拟重链剖分的形式在树上蹦跶。这样即可保证最终跳 次。
于是我们需要解决的问题便来了:
-
如何根据当前的位置,确定链头和公差?
首先确定如何划分链。由于链的端点可能被包含在若干条链中,因此我们将链底保存在链中,而将链头排除在链之外。换句话说,也就是按照深度左开右闭。
假设现在的位置是 ,那么公差自然是 。
这里有两种情况,一者如果 ,那么等差数列其实只有一项;否则,根据 Periodicity Lemma,我们可以得到链头应当为 ,因为“链头” 不应当算在链内。当然,这种划分方式也很好地处理了 的特殊情况。
-
如何移动两个点?
按照重链剖分的理论,合理的跳法应该是选择终点较深的一个点跳。
不过,由于原先 的顺序就是树的 DFS 序,所以我们暴力一步一步跳 的时候,的确可以每次移动 DFS 序较大的一个点。于是“合理”的迁移就是,能不能每次将编号较大的一个点移到链头?
不妨假设我们要移动 ,所以有 。如果 不会跳过 还好说。否则假设 会跳过 ,也就是说:
-
情况 1: 就是 。
这个比较容易。我们可以发现此时 ,它们同属一条链。
-
情况 2: 不是 。我们先来画个图:
为了方便,我们就用 指代 。条件告诉我们 。根据 KMP 算法流程,我们可以知道 是随 增大而单调不降的量,因此这种情况是不存在的。
2022.04.06 更新
上面这个部分其实可以更简洁。我们注意到一定有 ,而如果会跳过,则应该有 。根据 随 单调不降的性质,我们可以得出 ,所以跳过的情况一定意味着 共链。
所以我们只需要在跳点的过程中判断一下是否会出现情况 1 即可。
-
最终复杂度为 。实现代码无比简洁,并且跑得飞快。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!