P4156 论战捆竹竿 题解

论战捆竹竿

题意:给定字符串 s,计数 "串 t 的长度" 可能的种数有多少种,使得 t 能被 s 作为印章印出来,且 |t|wn=|s|5×105nw1018

第一步:
求出 s 的周期 {a1am},包含 nam=n)。转化为求 aibiwn 的情况下,aibi 的取值有多少种,要求 bi0。记 w0=wn

第二步:
aibi 的形式,考虑同余最短路。(当题目中出现类似 "若干个数求和" 的形式,可以考虑同余最短路
A=minai,令 Fi 表示 modA=i 的所有数中,能表示为 aibi 的最小数是多少。
如果这里直接跑最短路,一共有 A 个点,每个点通过 a1am 都会连出 m 条边,所以复杂度至少是 O(Am) 的。同时可以构造出来 s=aaaabaaaaa,使得周期数量达到 O(n) 个,同时周期的长度都是 n/2 的,肯定能被卡。

第三步:
我们需要改进这个方法。根据 border 理论,{a1am} 可以被分成 logn 个等差数列。
把每个等差数列单独拎出来,依次考虑。

考虑第 k 个等差数列 {x,x+d,x+2d,,x+td},构造 x 个点编号 0x1F(i) 表示如果使用前 k1 个等差数列中的数,它们能组成的数中,modx=i 的最小数是多少。
我们要用 F(i) 推出 Fnew(i):使用前 k 个等差数列中的数,它们能组成的数中,modx=i 的最小数是多少。

首先把同余最短路的图建出来。观察发现,按照 gcd(x,d) 分类,每一类之间没有边,内部有边。于是我们把 modgcd(x,d) 相等的一起处理。
也就是说,比如 gcd(x,d)=3,先把 F(0),F(3),F(6), 转移到 Fnew(0),Fnew(3),,然后再转移 F(1),F(4),F(2),F(5),,各自求解,然后拼出来 Fnew

如果还是把 modgcd(x,d) 相等的点拿出来跑最短路,还是没有优化。这里有一个破环为链的 DP 想法。举个例子,比如当前等差数列是 {15,24,33}gcd(15,9)=3,所以按 3 的余数分类。比如现在正在处理 F(1,4,7,10,13)。它们之间的边连出来应该是这样:

不妨 F(10) 是其中最小的点。我们以 10 这个点破环为链:只保留从前往后的边(不越界)。我们会证明,在这个链图上如果跑最短路,答案和环图是一样的。

证明:考虑到点 x 的最短路,假设破环为链的起点是 st。如果存在另一个点 y,走了一条不存在的边使得 dist[x] 更短了。但是因为 stF() 最小的,所以 F(st)<F(y);同时因为 y 走到 x 是越界的,所以 yx 一定比 stx 更远,根据等差数列的性质,st 一定存在一条比 yx 的边更短的。因为 F(st)<F(y),而且 st 出发还有更小的边,所以一定不会存在这样的 y

因此我们只需要保留这个链图跑最短路。但是真的需要跑最短路吗?是可以优化的。
记链上第 i 个点的 Fnew 值为 gi(从 0 开始编号)。首先可以写出一个朴素的 DP 方程。

gi=min{F(i),g[j]+x+(ij)d|itji1,j0}。这里 itt 是上面 x+tdt

这个式子很显然可以单调队列优化,于是复杂度从最短路和边数有关的复杂度,降低到 O(点数)

这一部分贡献的复杂度,对于每个等差数列会贡献 O(点数) 的复杂度,一共 logn 个等差数列,所以会贡献 O(nlogn) 的复杂度。

第四步:
第三步解决了从 F(i)Fnew(i) 的问题,但是我们还需要让 Fnew(i) 的模数变成第 k 个等差数列的 x,而不是第 k1 个等差数列的 x。例如当前模数(首项) x=15,下一个等差数列模数(首项) x=12。怎么把 F(i) 的定义从 mod15=i 的最小数,转化为 mod12=i 的最小数,从而更方便用 mod12F(i) 推出属于 x=12Fnew(i)

mod15F 记作 F(i)mod12F 记作 F(i)。新的模数记作 x

这里 F(i) 的更新取值分两种。

借一个具体的例子,比如 F(13)=28

第一种:因为 28mod12=4,所以我们知道 F(4) 可以取到 28。也就是如果 F(a)=b,那 F(bmodx)b

第二种:在 F 里 因为 F(13)=28,所以 28+15ω(ω0) 都可以取到。在 F 里对应着我们会用 F(13)+(15mod12)ω 去更新 F

考虑 F 的更新建成同余最短路的图,实际上每个点只向后方第 3 个点连边。

理解一下。这里 F 的同余最短路的建图和第三步的建图是不同的——F 只有一种边,就是向后走 15mod12=3 步的边。而第三步的建图有 {x,x+d,,x+td} 一共 t+1 种向后走的边。所以 F 的建图实际上就是一个环。

顺理成章地,沿用上面破环为链的想法。找到 mod15 的所有 F(i) 里最小的,记作 F(mn)。以 mn 号点为起点破环为链,得到一条 mnmn+15mod12mn+2(15mod12) 的链,然后在这条链上走一遍,也就是 F(mn+α(15mod12))F(mn)+15α

切换一次模数的复杂度是 O(点数) 的。一共切换 logn 次,也是 O(nlogn)

总共 O(nlogn)

posted @   FLY_lai  阅读(8)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示