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(在原来代码上魔改的)