luogu P3805 【模板】manacher算法

背景:

感觉GDOI会考字符串的题目。

KMP、AC自动机都考过了,后缀数组不想背模板,还是搞一搞manacher吧。

于是就看了一个视频

于是就搞懂了。



题意:

有一个字符串,求他的最长回文字串的长度。



思路:

manacher模板题。

表示回文树不会。

因为回文字串的长度有奇有偶,所以这个算法的第一个巧妙之处就是在每个字符中间加上#(或者其它无用的字符,但是为了尊重算法发明者的版权,就用#号吧)。

此时,最长回文字串的长度一定为奇数(埋一个坑,继续往下看)。

p[i]表示以i为中心的回文半径(即以i为中心的回文字串的长度/2);

id表示当前能拓展出去的最右边的回文字串的中心;

ma表示当前能拓展出去的最右边的回文字串的最右边的编号。

我们发现,对于你在匹配的一个字符,我们都有可能通过一个回文字串覆盖掉它(即ma>i),此时必然在id*2-i的位置出现一个刚刚好与它一一对应的字符(因为以id为中心,这两个字符左右对称)。——第二个巧妙之处。

那么此时我们必然还存在一个性质,即p[i]=min(p[id*2-i],ma-i)(好好理解,不是很好讲,或者说,我也不会)。

最后,暴力拓展即可。

答案为max(p[i]-1)(想想为什么减1,再看看前面的坑,因为在这个回文字串中,p[i]中包括一些#,并且i位置一定为#时p[i]-1的值最大,但这个#算了两遍,所以要减1)。



代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
	char s[11000010],st[22000010];
	int p[22000010];
	int len,ans=0;
void init()
{
	st[0]='!';
	st[1]='#';
	for(int i=0;i<len;i++)
	{
		st[2*i+2]=s[i];
		st[2*i+3]='#';
	}
	len=len*2+2;
	st[len]='@';
}
void manacher()
{
	int id=0,ma=0;
	for(int i=1;i<len;i++)
	{
		p[i]=ma>i?min(p[2*id-i],ma-i):1;
		for(;st[i+p[i]]==st[i-p[i]];p[i]++);
		if(p[i]+i>ma)
		{
			ma=p[i]+i;
			id=i;
		}
		ans=max(ans,p[i]-1);
	}
}
int main()
{
	scanf("%s",s);
	len=strlen(s);
	init();
	manacher();
	printf("%d",ans);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值