border与period学习笔记

border与period

起因是觉得自己对border这一套理论完全不会,来学一手

符号定义

以下默认 s​ 为一个字符串

s[i] 表示字符串 s 下标为 i 的字符

s[i,j] 表示字符串 s 下标位于 [i,j] 的子串

pre(s,x)​ 表示字符串 s​ 长度为 x 的前缀​

suf(s,x) 表示字符串 s 长度为 x 的后缀​

定义

0r<|s|,pre(s,r)=suf(s,r),则称 rs 的一个 border​​

0<p|s|,s[i]=s[i+p],i[1,|s|p]​,则称 p​ 为 s​ 的一个 period​​​(周期)

记最小周期为 per(s)

显然,rborder |s|rperiod

引理

Weak Periodicity Lemma

pq​ 是 s 的周期,p+q|s|,则 gcd(p,q) 也为 s 的周期

证明

不妨设 p<q,记 d=qp

由于 p+q|s|​,对于 i[1,|s|d]​,ip1i+q|s| 一定成立

若前者成立,si=sip=sip+q=si+d

若后者成立,si=si+q=si+qp=si+d

ds 的周期

不难发现这能形成一个辗转相减的过程,最终能得到 gcd(p,q)s 的周期

Periodicity Lemma

p​​ 和 q​​ 是 s​​ 的周期,p+qgcd(p,q)|s|​​,则 gcd(p,q)​​ 也为 s​​ 的周期

字符串匹配

众所周知,字符串匹配问题由KMP算法解决

引理:若字符串 s,t 满足 |s||v|2​,则​ st 中所有匹配位置构成一个等差数列,公差为 per(s)

证明

我们仅考虑匹配次数大于2的情况,否则显然为等差数列

由于 2|s||v|,所以任意两次匹配间必有交点,任意两次匹配位置之差为 s 的一个 period

考虑取出第一二次匹配 u1,u2,与某次匹配 ux

u1u2 匹配位置之差为 du2ux 的位置差为 q

易得 d,qsperiod,由 Weak Periodicity Lemma,可知 g=gcd(d,q) 也为一个周期

s 的最小周期 pgq|u1u2|,故 pu1u2 的周期,可得 pu1u2 的周期

p<du2 左移 p 产生匹配,故 pd,又 pg=gcd(d,q)d,所以 p=d

d|q,故结论成立,公差为 per(s)​(含3次匹配以上)

border​ 的结构

引理:字符串 s 所有不小于 |s|2border 构成一个等差数列

证明

s 最大的 bordernp,(p|s|2),另外某个 border​ 为 nq,(q|s|2)

由于 p,q​ 为 period​,由于 Weak Periodicity Lemma​​ 引理,gcd(p,q)period

ngcd(p,q)s 的一个 border,又 gcd(p,q)p,且 np 为最大的 border

gcd(p,q)=p,所以 p|q

故字符串 s 所有不小于 |s|2border 构成一个等差数列,公差为 p(最小 period

推论:字符串 s 的所有 border 长度排序后可分成 O(log|s|) 段, 每段是一个等差数列。

sborder 按长度 x 分成 log|s| 类,记 2k 为最大不超过 n2 的次幂

x[1,2),[2,4),,[2k1,2k),[2k,n)

对于 x[2k,n),显然 2kn2,根据引理该段构成一个等差数列

对于 x[2i1,2i)​,考虑证明其也是一个等差数列

对于长度相等的两个字符串 u,v,记 PS(u,v)={k|pre(u,k)=suf(v,k)}

LargePS(u,v)={kPS(u,v)|k|u|2}

那么 x[2i1,2i)​ 的 border 集合为 LargePS(pre(s,2i),suf(s,2i))

类似引理的证明,容易得到 LargePS(u,v) 构成一个等差数列

故结论得证

子串周期查询

给定字符串 s[1,n]​​,每次询问子串 t=s[l,r]​ 的所有周期,用 O(logn)​ 个等差数列表示

求出所有 border 即可

border​ 的结构划分

  1. border x[2i1,2i)

    uLargePS(pre(t,2i),suf(t,2i))​​,则 pre(t,2i1) 为其前缀,suf(t,2i1) 为其后缀

    我们仅需求出 pre(t,2i1)suf(t,2i) 中匹配的开头位置集合与 suf(t,2i1)pre(t,2i)​ 中匹配的结尾位置集合翻转后取交

    由于前面字符串匹配的结论,我们所求的匹配位置成一个等差数列

    考虑仅需求出第一二次和最后一次的匹配位置,我们就能算出等差数列的首项、公差和末项

    实现 succ(v,i),pred(v,i) 表示 vi 开始向前后的第一次匹配位置即可

    由于 v 的长度为 2 的次幂,考虑同后缀数组一半倍增,每次将数组记录下来,空间 O(nlogn)

    succ/pred​ 时二分即可得

    值得一提的是,上面求 succ/pred 的算法被称为 Internal Pattern Matching

    如何对等差数列取交?

    存在引理证明若所求两个等差数列长度都不少于3,则他们的公差相等,容易 O(1) 求交

    否则枚举小长度即可,复杂度 O(1)

  2. border x[2k,|t|)

    考虑将情况1的 2i 改为 |t|,仍然成立

目前为止,我们已经得到了时间 O(nlogn)O(log2n),空间 O(nlogn) 的做法

O(nlogn)O(log2n)​ 的做法暂时不大会(

[BJWC2018]Border 的四种求法

posted @   juju527  阅读(675)  评论(1编辑  收藏  举报
编辑推荐:
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 从 HTTP 原因短语缺失研究 HTTP/2 和 HTTP/3 的设计差异
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示