首先想要把这题 A 掉是很容易的,我们现在追求线性做法。
一个很自然的想法是枚举 (AB) 以及当前 (AB) 所对应的 (i)。这显然是一个调和级数复杂度,至于如何判断对于某个前缀,它是否可以分成 (i) 个相等的段即 (AB),这个哈希 / Z / KMP 都可以,Z 我最熟悉就写它了。这里说一下 KMP,若 (kmp_imid 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) ight)),稍卡常可以过。离线性的距离在于 (26) 和 (log),我们要把它们都去掉。接下来来找性质。
注意到,((AB)^x) 和 ((AB)^{x+2}) 的 (F) 值是一样的,那么它们对应的 (C) 的 (F) 值显然也是一样的。也就是说对于每轮枚举的 (AB),(i) 的贡献仅分为两种,算一下计量数然后对于每种单独算即可,至此去掉了调和级数的 (log)。
接下来发现,相邻两次枚举的长度相差 (1) 的 (AB),它们的 (F) 值的差是常数级别。然后 ((AB)^2) 也同理。于是我们可以放弃维护前缀和桶,直接维护桶,然后放个指针在里面游走,这样每次 (AB) 更新的复杂度是常数。也就成功线性了。
code(在原来代码上魔改的)