牛客 最长回文

传送门
有两个长度均为n的字符串A和B。可以从A中选一个可以为空的子串A[l1…r1],B中选一个可以为空的子串B[l2…r2],满足r1=l2,然后把它们拼起来(A[l1…r1]+B[l2…r2])。求用这样的方法能得到的最长回文串的长度。注意:求的不是本质不同的回文串个数哦!!!
对两个串分别跑manacher,然后我们枚举每个中心进行匹配。
以枚举A串的中心举例,如果是选择字母做中心,如果字母的位置为i,那么b串的i应该匹配A(新)串的i-2;如果是以符号“#”为中心,那么b串的i-1应该匹配的则是A串的i-1,注意l2=r1这个临界条件。也就是说b串开始位置和a串的开始位置重合。

#include
using namespace std;
const int maxn=2e6+50;
char a[maxn],newa[maxn];
int p1[maxn];
char b[maxn],newb[maxn];
int p2[maxn];
int init1(){
	int len=strlen(a);
	newa[0]='$';
	newa[1]='#';
	int j=2;
	for(int i=0;i<len;i++){
		newa[j++]=a[i];
		newa[j++]='#';
	}
	newa[j]='\0';
	return j;
}
int init2(){
	int len=strlen(b);
	newb[0]='$';
	newb[1]='#';
	int j=2;
	for(int i=0;i<len;i++){
		newb[j++]=b[i];
		newb[j++]='#';
	}
	newb[j]='\0';
	return j;
}
void manacher1(){
	int len=init1();
	int id;
	int mx=0;
	for(int i=1;i<len;i++){
		if(i<mx)
			p1[i]=min(p1[2*id-i],mx-i);
		else 
			p1[i]=1;
		while(newa[i-p1[i]]==newa[i+p1[i]])
			p1[i]++;
		if(mx<i+p1[i]) id=i,mx=i+p1[i];
	}
}
void manacher2(){
	int len=init2();
	int id;
	int mx=0;
	for(int i=1;i<len;i++){
		if(i<mx)
			p2[i]=min(p2[2*id-i],mx-i);
		else
			p2[i]=1;
		while(newb[i-p2[i]]==newb[i+p2[i]])
			p2[i]++;
		if(mx<i+p2[i])id=i,mx=i+p2[i];
	}
}
int main(){
	int n;
	scanf("%d",&n);
	scanf("%s",a);
	scanf("%s",b);
	manacher1();
	manacher2();
	int ans=1;
	n=(n+1)*2;
	for(int i=2;i<=n;i++){//其实是在匹配'#'
		int tmp=max(p1[i],p2[i-2]);
		while(newa[i-tmp]==newb[i+tmp-2])tmp++;
		ans=max(ans,tmp);
	}
	printf("%d\n",ans-1);
	return 0;
}

你可能感兴趣的:(manacher)