manacher 变种之神秘等号

某机房因为不知道 T1 改题面集体爆零了,怎么回事呢?

某人因为不知道出题人下发的 Poly 模板到底要开几倍空间导致 RE 一堆,怎么回事呢?

某题代码只因一个等号之差复杂度有翻天覆地的变化,怎么回事呢?

这究竟是道德的扭曲还是人性的沦丧?请收看大型纪录片五星算法 manacher 传奇


根据某湖南省队集训题以及某联考题,我们可以发现 manacher 算法是一个变化多端而且考点看似少实则多。暴论:manacher 才是字符串神级算法。

假设我们改造了 manacher 使其维护了一定的信息,这个信息表现成一个类回文串的性质,支持同时加入或删除头尾,并且满足类似回文串的翻转性质(一个大结构包含另一个小结构时,你翻转内部那个小结构的位置可以得到对称位置的信息,讲得很抽象但学过 manacher 的应该知道我在说什么),我们就可以使用 manacher 求出以每个位置作为中心扩展到不能再扩展的所有串的所有信息。

具体做法跟 manacher 几乎一模一样,维护一个最大右端点 \(mx\) 及取到这个右端点的回文中心 \(pos\),然后在继承信息的时候,普通 manacher 由于信息可以直接截断所以说直接 r[i]=min(r[2*pos-i],mx-i) 这样子就行了,改造后就是直接不断的删除 \(2pos-i\) 处极长串的两端直到其半径 \(\leq mx-i\)

有人说,你这个暴力截断不是假飞了!我们随随便便卡!在知道的人都知道的某题中我们造一段连续下降一段连续上升的数据似乎可以轻松卡掉。

然而之所以能够卡掉是因为我们锁定了一个一直不变的 \(pos\),这样有多个串对着同一个边界疯狂取整。

为啥 \(pos\) 一直不变呢?

众所周知,在 manacher 算法中我们更新右端点一般写 if(i+r[i]>mx) mx=i+r[i],pos=i,毕竟大多数人 checkmax 时都是喜欢写 if(a>b) a=b; 嘛!也许真的有很多人喜欢写 \(\ge\)

事实上我们改成 if(i+r[i]>=mx) mx=i+r[i],pos=i,那么变种 manacher 就是正确的了!为什么?

因为我们每一次截断如果发生了都一定会更新 \(mx\)\(pos\),使得 \(pos=i\)。这样 \(pos\) 就右移了 \(i-pos\) 个位置。

\(t=2pos-i\) 分析一下,我们单次暴力截断复杂度是 \((pos-r_{pos})-(t-r_t)\),其中 \(r_x\)\(x\) 为中心的最大半径。而由于 \(mx=pos+r_{pos}\),所以 \(t+r_t\le pos+r_{pos}\),这意味着 \(r_t-r_{pos}\le pos-t\),所以 $(pos-r_{pos})-(t-r_t)= pos-t+(r_t-r_{pos})\le 2(pos-t)=2(i-pos) $,而由于 \(pos\) 的总位移是 \(O(n)\) 的,则暴力截断的复杂度也是 \(O(n)\)

所以懂得都懂的某道题复杂度就是 \(O(n)\) 的。许多人写了挂 \(\log\) 的做法然后被卡常了 QwQ。

posted @ 2024-05-28 17:44  yyyyxh  阅读(44)  评论(0编辑  收藏  举报