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];
		}
	}
}
posted @ 2022-02-24 11:50  cbdsopa  阅读(91)  评论(0编辑  收藏  举报