【洛谷P3805】【模板】manacher算法

题目

题目链接:https://www.luogu.com.cn/problem/P3805
给出一个只由小写英文字符 \(\texttt a,\texttt b,\texttt c,\ldots\texttt y,\texttt z\) 组成的字符串 \(S\) ,求 \(S\) 中最长回文串的长度 。

字符串长度为 \(n\)

思路

先将每两个字母之间插入一个奇怪的符号。
\(p[x]\) 表示第 \(x\) 个字符为对称中心,能扩展的最远距离是多少。记 \(mid,mr\) 分别为所有便利过的区间中右端点最远时的对称中心和右端点最大值。

  • \(x\leq mr\) 时,显然 \(p[x]=min(p[x],2\times mid-x)\)
  • \(x>mr\) 时,暴力扩展即可。
    由于 \(mid\) 单调增,所以时间复杂度 \(O(n)\)

代码

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

const int N=11000010;
int n,p[N*2];
char s[N*2];

int manacher(char *s)
{
	int ans=0,mid=0,mr=0;
	for (int i=2;i<n;i++)
	{
		if (i<=mr) p[i]=min(p[mid*2-i],mr-i+1);
		while (s[i-p[i]-1]==s[i+p[i]+1]) p[i]++;
		if (i+p[i]-1>mr) mid=i,mr=i+p[i]-1;
		ans=max(ans,p[i]);
	}
	return ans;
}

int main()
{
	scanf("%s",s+1);
	n=strlen(s+1);
	for (int i=n*2;i>=1;i-=2) s[i]=s[i/2];
	for (int i=n*2-1;i>=1;i-=2) s[i]='#';
	s[n*2+1]=s[0]='#'; n=n*2+1;
	printf("%d",manacher(s));
	return 0;
}
posted @ 2020-10-03 20:50  stoorz  阅读(94)  评论(0编辑  收藏  举报