manacher
简单说一下,首先我们类似扩展KMP一样的维护右端点最右的区间。我们直接把当前的点放到这个最右区间内翻转,直接用这个翻转的位置更新回文长度,然后由于不能保证区间外的回文性,于是取个min,具体看代码。
然后为了统一处理奇偶回文,我们在字符直接以及字符串开头结尾添加 #
,代表空。那么对于一个偶数 \(k\) ,奇回文原串中最长扩展长度为 \(k+1\) ,重构串中为 \(2k+3\) (必定从字符位置开始,以空位置结尾),减一就是最长回文长度。偶回文最长扩展长度 \(k\) ,重构串中为 \(2k+1\) (必定从空位置开始,空位置结束),减一也是最长回文长度。所以减一就可以直接用了。而且全变成了重构串中的奇回文,统一处理即可。
inline void build(){
for(int i=1;i<=n;++i){
s[2*i-1]='#';
s[2*i]=c[i];
}
s[2*n+1]='#';
}
int d[N<<1];
inline void manacher(){
int l=0,r=-1;
for(int i=1;i<=2*n+1;++i){
if(i<=r) d[i]=std::min(d[r-i+l],r-i+1);
while(i+d[i]<=2*n+1 and i-d[i]>=1 and s[i+d[i]]==s[i-d[i] ])
++d[i];
--d[i];//这个位置是'#'
if(i+d[i]>r){
r=i+d[i];l=i-d[i];
}
}
}