manacher 算法

manacher 算法

题目大意:求最长回文子串的长度(题目

分析:

  1. 设字符串为\(S\),首先我们要寻找它的对称中心,但发现对称中心可能在一个字符上,也可能在两个字符中间如图因为在两个字符中间的我们不好访问,于是我们可以在中间插入一些无关的字符,让字符来代替中间的空隙在这里插入图片描述
  2. 我们记录一个数组\(P\)\(P_i\)表示以\(S_i\)为中心的回文数列的最大半径在这里插入图片描述如图,\(P_7=6\),在记录\(mid,r\),表示当前已知的\(P_i\)中,\(P_{mid}+r\)是最大的,即右区间离\(S_{S.length()}\)最近
  3. 于是对于一个未知的\(P_i\)如果\(i \leqslant P_{mid}+r\)那么就可以根据回文数的对称性,确定在\(mid-r \leqslant i \leqslant {mid}+r\)这段区间里,\(P_i=min(P_{关于mid对称的点},mid+r-i)\),易得对称点为\(2*mid-i\),于是\(P_i=min(P_{2*mid-i},mid+r-i)\)
  4. 但是我们不知道\(mid+r\)后面是否还有相同的\(P_x,P_y\),所以要暴力枚举,最后更新\(mid,r\)
  5. 于是最大值就是\(P_{max}\)

代码实现:

#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;

void read(int &sum)
{
	sum=0;char last='w',ch=getchar();
	while (ch<'0' || ch>'9') last=ch,ch=getchar();
	while (ch>='0' && ch<='9') sum=sum*10+ch-'0',ch=getchar();
	if (last=='-') sum=-sum;
}
char s[11000002*2],g[11000002*2];
int p[11000002*2];
int len;
int main()
{
//	freopen("M.in","r",stdin);
//	freopen("M.out","w",stdout);
	s[++len]='|';
	char ch=getchar();
	while (ch!=EOF)
	{
		s[++len]=ch;
		s[++len]='|';
		ch=getchar();
	}
	int mmax=0;
//	for (int i=1;i<=len;i++) printf("%c",s[i]);
	for (int i=1,r=0,mid=0;i<=len;i++)
	{
		if (i<=mid+r) p[i]=min(p[2*mid-i],mid+r-i+1);
		while (i-p[i]>=1 && i+p[i]<=len && s[i-p[i]]==s[i+p[i]]) p[i]++;
		if (s[i-p[i]]!=s[i+p[i]] || i-p[i]<1 || i+p[i]>len) p[i]--;
		if (i+p[i]>r) r=p[i],mid=i;
		mmax=max(mmax,p[i]);
	}
//	printf("\n");
	printf("%d",mmax);
//	fclose(stdin);fclose(stdout);
	return 0;
}
posted @ 2021-10-17 10:30  WBWYX  阅读(31)  评论(0)    收藏  举报