【国家集训队】最长双回文串(Manacher算法)

题目描述见原题。

分析

首先这题用其他方法做也可行,但manacher应该是最优方法了。

设一个Lmax[i],表示从i开始算上i向左的最大回文串长度;设一个Rmax[i]表示从i开始算上i最大回文串长度。如果能处理出这两个东西就可以直接出答案。

首先可以在求每个点的最长回文半径时初步求出上述两个数组,然后进行递推。

Lmax是一个点往左扩展,越靠右越可能长,所以做逆推;Rmax是一个点往右扩展,越靠左越可能长,所以做顺推。递推式子见代码。

处理好之后扫一遍就出解了。

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
using namespace std;
const int MAXN=100005;
int N=0,Lmax[MAXN*2],Rmax[MAXN*2],p[MAXN*2];
char s[MAXN*2],a[MAXN];

int main()
{
	scanf("%s",a);
	
	int len=strlen(a),i,mid=0,maxright=0;
	s[N]='$';s[++N]='#';
	for(i=0;i<len;i++) s[++N]=a[i],s[++N]='#';
	
	for(i=1;i<=N;i++)
	{
		p[i]=maxright>i?min(p[mid*2-i],maxright-i):1;
		while(s[i+p[i]]==s[i-p[i]]) p[i]++;
		if(i+p[i]-1>maxright)maxright=i+p[i]-1,mid=i;
		
		Lmax[i+p[i]-1]=max(Lmax[i+p[i]-1],p[i]-1);  //初步求出两个数组 
		Rmax[i-p[i]+1]=max(Rmax[i-p[i]+1],p[i]-1);
	}
	
	int ans=0;
	for(i=1;i<=N;i+=2) Rmax[i]=max(Rmax[i],Rmax[i-2]-2);
	for(i=N;i>=1;i-=2) Lmax[i]=max(Lmax[i],Lmax[i+2]-2);
	
	for(i=1;i<=N;i++) ans=max(ans,Lmax[i]+Rmax[i]);
	cout<<ans;
	
	return 0;
}

猜你喜欢

转载自blog.csdn.net/WWWengine/article/details/81501397
今日推荐