回文自动机

构造
和AC自动机及其类似
相比Manacher,它还可以统计某个回文子串的数量,结尾为\(i\)的回文串数量,大小(更方便)

节点

一个字符串总共有有\(n\)个本质不同的回文串

证明:对于每个右端点\(i\),每次只有多出至多\(1\)个回文串,多出的是最长的回文串
因为其他的均能通过在最长串中点对称,找到相应的右端点在之前的回文串,所以至多只有\(1\)

根据上述结论,只要找出所有右端点对应的最长回文串,即可找到所有本质不同的回文串(Manacher扩展r时)
这样就可以以本质不同的回文串作为节点,正好完全包括了全部的字符串且不重不漏

fail指针——回文树

显然fail指针指向上一个回文串后缀

构造(略)

模板

Luogu P3649 [APIO2014]回文串
注意nxt一定最后赋值

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

const int N=3e5+5;
int n,lst,tot,len[N],pa[N],nxt[N][26],c[N],b[N];
ll a[N];
char s[N];
inline void PAM(int ch,int n) {
	int u=lst;
	while(s[n-len[u]-1]!=s[n]) u=pa[u];
	if(!nxt[u][ch]) {
		int now=++tot; len[now]=len[u]+2;
		int v=pa[u];
		while(s[n-len[v]-1]!=s[n]) v=pa[v];
		pa[now]=nxt[v][ch];
		nxt[u][ch]=now;
	}
	lst=nxt[u][ch];
	a[lst]++;
}

int main(){
	scanf("%s",s+1); n=strlen(s+1);
	pa[1]=0,pa[0]=1,len[1]=-1; lst=0; tot=1;
	for(int i=1;i<=n;i++) {
		PAM(s[i]-='a',i);
	}
	for(int i=2;i<=tot;i++) c[len[i]]++;
	for(int i=2;i<=n;i++) c[i]+=c[i-1];
	for(int i=tot;i>1;i--) {
		b[c[len[i]]--]=i;
	} 
	for(int i=tot-1;i>=1;i--) {
		int u=b[i]; a[pa[u]]+=a[u];
	}
	ll ans=1;
	for(int i=2;i<=tot;i++) {
		ans=max(ans,a[i]*len[i]);
	}
	printf("%lld\n",ans);
	return 0;

}
posted @ 2021-03-06 11:42  wwwsfff  阅读(85)  评论(0)    收藏  举报