border与period
起因是觉得自己对border这一套理论完全不会,来学一手
符号定义
以下默认 s 为一个字符串
s[i] 表示字符串 s 下标为 i 的字符
s[i,j] 表示字符串 s 下标位于 [i,j] 的子串
pre(s,x) 表示字符串 s 长度为 x 的前缀
suf(s,x) 表示字符串 s 长度为 x 的后缀
定义
若 0≤r<|s|,pre(s,r)=suf(s,r),则称 r 为 s 的一个 border
若 0<p≤|s|,s[i]=s[i+p],∀i∈[1,|s|−p],则称 p 为 s 的一个 period(周期)
记最小周期为 per(s)
显然,r 为 border ⟺ |s|−r 为 period
引理
Weak Periodicity Lemma
若 p 和 q 是 s 的周期,p+q≤|s|,则 gcd(p,q) 也为 s 的周期
证明:
不妨设 p<q,记 d=q−p
由于 p+q≤|s|,对于 ∀i∈[1,|s|−d],i−p≥1∨i+q≤|s| 一定成立
若前者成立,si=si−p=si−p+q=si+d
若后者成立,si=si+q=si+q−p=si+d
故 d 为 s 的周期
不难发现这能形成一个辗转相减的过程,最终能得到 gcd(p,q) 为 s 的周期
Periodicity Lemma
若 p 和 q 是 s 的周期,p+q−gcd(p,q)≤|s|,则 gcd(p,q) 也为 s 的周期
字符串匹配
众所周知,字符串匹配问题由KMP算法解决
引理:若字符串 s,t 满足 |s|≥|v|2,则 s 在 t 中所有匹配位置构成一个等差数列,公差为 per(s)
证明:
我们仅考虑匹配次数大于2的情况,否则显然为等差数列
由于 2|s|≥|v|,所以任意两次匹配间必有交点,任意两次匹配位置之差为 s 的一个 period

考虑取出第一二次匹配 u1,u2,与某次匹配 ux
记u1 与 u2 匹配位置之差为 d,u2 与 ux 的位置差为 q
易得 d,q 为 s 的 period,由 Weak Periodicity Lemma,可知 g=gcd(d,q) 也为一个周期
设 s 的最小周期 p≤g≤q≤|u1∩u2|,故 p 为 u1∩u2 的周期,可得 p 为 u1∪u2 的周期
若 p<d 则 u2 左移 p 产生匹配,故 p≥d,又 p≤g=gcd(d,q)≤d,所以 p=d
则 d|q,故结论成立,公差为 per(s)(含3次匹配以上)
border 的结构
引理:字符串 s 所有不小于 |s|2 的 border 构成一个等差数列
证明:
记 s 最大的 border 为 n−p,(p≤|s|2),另外某个 border 为 n−q,(q≤|s|2)
由于 p,q 为 period,由于 Weak Periodicity Lemma 引理,gcd(p,q) 为 period
则 n−gcd(p,q) 为 s 的一个 border,又 gcd(p,q)≤p,且 n−p 为最大的 border
故 gcd(p,q)=p,所以 p|q
故字符串 s 所有不小于 |s|2 的 border 构成一个等差数列,公差为 p(最小 period )
推论:字符串 s 的所有 border 长度排序后可分成 O(log|s|) 段, 每段是一个等差数列。
将 s 的 border 按长度 x 分成 log|s| 类,记 2k 为最大不超过 n 的 2 的次幂
x∈[1,2),[2,4),…,[2k−1,2k),[2k,n)
对于 x∈[2k,n),显然 2k≥n2,根据引理该段构成一个等差数列
对于 x∈[2i−1,2i),考虑证明其也是一个等差数列
对于长度相等的两个字符串 u,v,记 PS(u,v)={k|pre(u,k)=suf(v,k)}
记 LargePS(u,v)={k∈PS(u,v)|k≥|u|2}
那么 x∈[2i−1,2i) 的 border 集合为 LargePS(pre(s,2i),suf(s,2i))
类似引理的证明,容易得到 LargePS(u,v) 构成一个等差数列
故结论得证
子串周期查询
给定字符串 s[1,n],每次询问子串 t=s[l,r] 的所有周期,用 O(logn) 个等差数列表示
求出所有 border 即可
按 border 的结构划分
-
border x∈[2i−1,2i)
若 u∈LargePS(pre(t,2i),suf(t,2i)),则 pre(t,2i−1) 为其前缀,suf(t,2i−1) 为其后缀
我们仅需求出 pre(t,2i−1) 在 suf(t,2i) 中匹配的开头位置集合与 suf(t,2i−1) 在 pre(t,2i) 中匹配的结尾位置集合翻转后取交
由于前面字符串匹配的结论,我们所求的匹配位置成一个等差数列
考虑仅需求出第一二次和最后一次的匹配位置,我们就能算出等差数列的首项、公差和末项
实现 succ(v,i),pred(v,i) 表示 v 从 i 开始向前后的第一次匹配位置即可
由于 v 的长度为 2 的次幂,考虑同后缀数组一半倍增,每次将数组记录下来,空间 O(nlogn)
用 succ/pred 时二分即可得
值得一提的是,上面求 succ/pred 的算法被称为 Internal Pattern Matching
如何对等差数列取交?
存在引理证明若所求两个等差数列长度都不少于3,则他们的公差相等,容易 O(1) 求交
否则枚举小长度即可,复杂度 O(1)
-
border x∈[2k,|t|)
考虑将情况1的 2i 改为 |t|,仍然成立
目前为止,我们已经得到了时间 O(nlogn)−O(log2n),空间 O(nlogn) 的做法
O(nlogn)−O(log2n) 的做法暂时不大会(
[BJWC2018]Border 的四种求法
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现