P7114 - 字符串匹配 更优秀的 sol

首先想要把这题 A 掉是很容易的,我们现在追求线性做法。

一个很自然的想法是枚举 \(AB\) 以及当前 \(AB\) 所对应的 \(i\)。这显然是一个调和级数复杂度,至于如何判断对于某个前缀,它是否可以分成 \(i\) 个相等的段即 \(AB\),这个哈希 / Z / KMP 都可以,Z 我最熟悉就写它了。这里说一下 KMP,若 \(kmp_i\mid i\)\(i-kmp_i\) 是最小循环节,判一下整除就可以了。

然后问题是对于一个 \(AB\)\(C\) 如何求出满足 \(F(A)\leq F(C)\) 的将 \(AB\) 一刀两断的方案数?我们考虑预处理出前后缀 \(F\) 值,容易线性。然后在 \(AB\) 长度递增的同时,一边推一边把新的 \(A\)\(F\) 值扔到前缀和桶里(大小为 \(26\)),然后对 \(F(C)\) 查值即可。是我的考场代码。

那么这样是 \(\mathrm O\!\left(Tn(26+\log n)\right)\),稍卡常可以过。离线性的距离在于 \(26\)\(\log\),我们要把它们都去掉。接下来来找性质。

注意到,\((AB)^x\)\((AB)^{x+2}\)\(F\) 值是一样的,那么它们对应的 \(C\)\(F\) 值显然也是一样的。也就是说对于每轮枚举的 \(AB\)\(i\) 的贡献仅分为两种,算一下计量数然后对于每种单独算即可,至此去掉了调和级数的 \(\log\)

接下来发现,相邻两次枚举的长度相差 \(1\)\(AB\),它们的 \(F\) 值的差是常数级别。然后 \((AB)^2\) 也同理。于是我们可以放弃维护前缀和桶,直接维护桶,然后放个指针在里面游走,这样每次 \(AB\) 更新的复杂度是常数。也就成功线性了。

code(在原来代码上魔改的)

posted @ 2020-12-17 19:32  ycx060617  阅读(105)  评论(0编辑  收藏  举报