[SHOI2011]双倍回文

在这里插入图片描述

在建立PAM求len的同时,我们要求出trans。

trans 指针的含义是小于等于当前节点长度的一半最长回文后缀。

当我们新建一个节点后,如果它的长度小于等于 2,那么这个节点的 trans 指针指向它的 fail 节点

否则的话,我们同理从它父亲的 trans 指针指向的节点开始跳 fail 指针

直到跳到某一个节点所表示的回文串的两侧都能扩展这个字符

并且拓展后的长度小于等于当前节点长度的一半

那么新建节点的 trans 的指针就指向该节点的儿子


AC代码:

#pragma GCC optimize("-Ofast","-funroll-all-loops")
#include<bits/stdc++.h>
//#define int long long
using namespace std;
const int N=5e5+10;
struct PAM{
	int nex[N][26],fail[N],len[N],tot,last,trans[N];
	inline void init(){len[0]=0,len[1]=-1,fail[0]=fail[1]=1,tot=1,last=0;}
	inline int insert(int x,int en,char *s){
		int rt=last;
		while(s[en]!=s[en-len[rt]-1]) rt=fail[rt];
		if(!nex[rt][x]){
			int tmp=fail[rt];	++tot;
			while(s[en]!=s[en-len[tmp]-1]) tmp=fail[tmp];
			fail[tot]=nex[tmp][x];
			nex[rt][x]=tot;
			len[tot]=len[rt]+2;
			if(len[tot]<=2)	trans[tot]=fail[tot];
			else{
				int t=trans[rt];
				while(s[en-len[t]-1]!=s[en]||((len[t]+2)<<1)>len[tot]) t=fail[t];
				trans[tot]=nex[t][x];
			}
		}
		last = nex[rt][x];
		return len[last];
	}
}p;
char a[N];	int n,res;
signed main(){
	scanf("%d %s",&n,a+1);	p.init();
	for(int i=1;i<=n;i++)	p.insert(a[i]-'a',i,a);
	for(int i=2;i<=p.tot;i++)
		if((p.len[p.trans[i]]<<1)==p.len[i]&&p.len[p.trans[i]]%2==0)
			res=max(res,p.len[i]);
	cout<<res;
	return 0;
}
发布了417 篇原创文章 · 获赞 228 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_43826249/article/details/103934481