P3805 Manacher模板

#include<bits/stdc++.h>
using namespace std;

const int N=11000005;
char s[N<<1];
int n,p[N<<1];
//p[i]:以s[i]为中心的回文串的回文半径
//回文半径:对于a|b|a来说,其回文中心为'b',回文半径为"a|b"或"b|a"的长度,即3
//为什么叫半径?很显然,回文串一定是对称的(不然呢)

void input(){
	char ch=getchar();
	s[0]='~';//左边的哨兵节点(右侧的为\0)
	s[n=1]='|';//插入隔板(强行将长度为奇数的情况转化为偶数的情况)
	while(ch<'a' || ch>'z') ch=getchar();
	while(ch>='a' && ch<='z'){
		s[++n]=ch;
		s[++n]='|';
		ch=getchar();
	}
}

int main(){
	cin.tie(nullptr)->sync_with_stdio(false);
	input();
	
	int ans=0;
	for(int i=1,r=0,mid=0;i<=n;i++){
		//i,r,mid:当前扫描到的下标、已经确定的右边界、已经确定的右侧最靠右的回文串的对称中心
		if(i<=r) p[i]=min(p[2*mid-i],r-i+1);
		//核心思想当我们拓展到一个新字符时,不必重新从当前位置开始向左向右扫描,可以事先确定一部分回文半径
		//若i在已确定的右边界内,其回文半径就是其对称点的回文半径(当然,不能越界)
		while(s[i-p[i]]==s[i+p[i]]) p[i]++;//暴力拓展边界(最多拓展n次,且不回头,所以时间复杂度时O(n))
		if(i+p[i]-1>r){//产生了新的右边界(注意,是闭区间)
			r=i+p[i]-1;
			mid=i;
		}
		ans=max(ans,p[i]);
	}
	
	cout<<ans-1<<'\n';
	//一个回文串在在原串中的长度为L,经过转化后变为2L+1,其回文半径为L+1,所以答案要-1
	return 0;
}

posted on 2026-10-30 14:14  _CENSORED  阅读(4)  评论(0)    收藏  举报

导航