P3649 - 回文串 题解

这大概是个 PAM 题,而我们用 Manacher + SA 做。那么如何取代 PAM 这么强大的功能呢?这里有一条在回文子串题中的强大定理(是 yxh 教我的,后来我又到度娘上证实了一下):一个串的本质不同回文子串个数为 \(\mathrm O(n)\)。证明及分布:考虑归纳,假设 \(a_{1\sim i-1}\) 满足,那么现在考虑以 \(i\) 结尾的回文子串们。那么根据回文的性质,非最长者一定包含在最长者中而被对称到最长者开头,此时结尾不可能是 \(i\),根据假设一定被在 \(a_{1\sim i-1}\) 中算过。于是只需要算最长者即可(不过不保证最长者没有被重复算)。

那么大部分关于求整串的所有回文子串的信息的题,都可以用这个结论秒掉(除了洛谷上 PAM 模板题,强制在线加入字符就比较恶心)。例如本题,考虑如何求出每个点结尾的最长回文子串,首先先隔一个打一个分隔符,然后 Manacher,每个中心显然会更新某个区间的值。那就差分一波,set 扫一遍即可得到以每个点结尾的最长回文子串的中心。

然后因为这题是要求所有回文子串的某个函数值的 max,所以不用去重。直接考虑对每个回文子串求出现次数。这大概是 SA 的经典用法之一,不过我好像以前从来没用到过?设这个子串为 \([l,r]\),那么 \([l',l'+r-l]\) 与之相等当且仅当 \(\mathrm{LCP}(l,l')\geq r-l+1\)。那么后缀排序之后,满足条件的 \(l'\) 显然是一个区间,我们只需要找出最靠近某一个位置的满足 \(hi_x<c\) 的两个 \(x\) 即可。这个没像区间前驱后继这么毒瘤,这个只需要线段树上二分即可,就每个节点记录最小 \(hi\) 值即可。

Manacher + SA + 线段树二分板子三合一,轻微卡常,不全开 ll(如果全开 ll 还会 MLE。。。) + O2 就 A 掉了。

code

posted @ 2021-04-15 22:32  ycx060617  阅读(70)  评论(0编辑  收藏  举报