类似AC自动机的一种回文串匹配自动机,也就是一棵字符树。
准确的说,是两颗字符树
0号表示回文串长度为偶数的树,1号表示回文串长度为奇数的树
每一个节点都代表一个字符串,并且类似AC自动机那样,有字符基个儿子
它的第i个儿子就表示将字符基的第i个字符接到它表示的字符串两边形成的字符串
BZOJ3676
给定一个字符串,找出这个字符串所有的回文子串,然后找一个回文子串出现次数×回文子串长度的最大值
用manacher找出本质不同的回文串,每个串在后缀自动机上查询出现次数
1 #include<set> 2 #include<map> 3 #include<ctime> 4 #include<queue> 5 #include<cmath> 6 #include<cstdio> 7 #include<vector> 8 #include<cstring> 9 #include<cstdlib> 10 #include<iostream> 11 #include<algorithm> 12 #define ll long long 13 using namespace std; 14 int read() 15 { 16 int x=0,f=1;char ch=getchar(); 17 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 18 while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} 19 return x*f; 20 } 21 ll ans; 22 int bin[20]; 23 int n,p[300005]; 24 char ch[300005]; 25 struct sam{ 26 int last,cnt; 27 int fa[600005],a[600005][26],mx[600005],size[600005]; 28 int v[300005],q[600005],pos[600005],dep[600005],an[600005][19]; 29 sam(){ 30 last=++cnt; 31 } 32 void extend(int c,int id){ 33 int p=last,np=last=++cnt;mx[np]=mx[p]+1; 34 size[np]=1;pos[id]=last; 35 while(p&&!a[p][c])a[p][c]=np,p=fa[p]; 36 if(!p)fa[np]=1; 37 else 38 { 39 int q=a[p][c]; 40 if(mx[p]+1==mx[q])fa[np]=q; 41 else 42 { 43 int nq=++cnt;mx[nq]=mx[p]+1; 44 memcpy(a[nq],a[q],sizeof(a[q])); 45 fa[nq]=fa[q]; 46 fa[np]=fa[q]=nq; 47 while(a[p][c]==q)a[p][c]=nq,p=fa[p]; 48 } 49 } 50 } 51 void pre(){ 52 for(int i=1;i<=cnt;i++)v[mx[i]]++; 53 for(int i=1;i<=n;i++)v[i]+=v[i-1]; 54 for(int i=cnt;i;i--)q[v[mx[i]]--]=i; 55 for(int i=cnt;i;i--) 56 { 57 int t=q[i]; 58 size[fa[t]]+=size[t]; 59 } 60 for(int i=1;i<=cnt;i++) 61 { 62 int t=q[i]; 63 dep[t]=dep[fa[t]]+1; 64 an[t][0]=fa[t]; 65 for(int j=1;bin[j]<=dep[t];j++) 66 an[t][j]=an[an[t][j-1]][j-1]; 67 } 68 } 69 void query(int l,int r){ 70 int mid=pos[r]; 71 for(int i=18;i>=0;i--) 72 { 73 int t=an[mid][i]; 74 if(mx[t]>=r-l+1)mid=t; 75 } 76 ans=max(ans,(ll)size[mid]*(r-l+1)); 77 } 78 }sam; 79 void manacher() 80 { 81 int mx=0,id; 82 for(int i=1;i<=n;i++) 83 { 84 if(mx>i)p[i]=min(mx-i,p[2*id-i-1]); 85 else p[i]=0; 86 while(ch[i+p[i]+1]==ch[i-p[i]]) 87 { 88 p[i]++; 89 sam.query(i-p[i]+1,i+p[i]); 90 } 91 if(p[i]+i>mx)mx=p[i]+i,id=i; 92 } 93 mx=0; 94 for(int i=1;i<=n;i++) 95 { 96 if(mx>i)p[i]=min(mx-i-1,p[2*id-i]); 97 else {p[i]=1;sam.query(i-p[i]+1,i+p[i]-1);} 98 while(ch[i+p[i]]==ch[i-p[i]]) 99 { 100 p[i]++; 101 sam.query(i-p[i]+1,i+p[i]-1); 102 } 103 if(p[i]+i>mx)mx=p[i]+i,id=i; 104 } 105 } 106 int main() 107 { 108 bin[0]=1;for(int i=1;i<20;i++)bin[i]=bin[i-1]<<1; 109 scanf("%s",ch+1); 110 n=strlen(ch+1); 111 for(int i=1;i<=n;i++)sam.extend(ch[i]-'a',i); 112 sam.pre(); 113 ch[0]='+';ch[n+1]='*'; 114 manacher(); 115 printf("%lld\n",ans); 116 return 0; 117 }
然后是一道回文自动机裸题
1 #include<set> 2 #include<map> 3 #include<ctime> 4 #include<queue> 5 #include<cmath> 6 #include<cstdio> 7 #include<vector> 8 #include<cstring> 9 #include<cstdlib> 10 #include<iostream> 11 #include<algorithm> 12 #define ll long long 13 using namespace std; 14 int read() 15 { 16 int x=0,f=1;char ch=getchar(); 17 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 18 while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} 19 return x*f; 20 } 21 ll ans; 22 int n; 23 char ch[300005]; 24 struct pam{ 25 int cnt,last; 26 int a[300005][26],fa[300005],l[300005],size[300005]; 27 pam(){ 28 cnt=1;fa[0]=fa[1]=1;l[1]=-1; 29 } 30 void extend(int c,int n){ 31 int p=last; 32 while(ch[n-l[p]-1]!=ch[n])p=fa[p]; 33 if(!a[p][c]) 34 { 35 int now=++cnt,k=fa[p]; 36 l[now]=l[p]+2; 37 while(ch[n-l[k]-1]!=ch[n])k=fa[k]; 38 fa[now]=a[k][c];a[p][c]=now; 39 } 40 last=a[p][c]; 41 size[last]++; 42 } 43 void solve(){ 44 for(int i=cnt;i;i--) 45 { 46 size[fa[i]]+=size[i]; 47 ans=max(ans,(ll)size[i]*l[i]); 48 } 49 } 50 }pam; 51 int main() 52 { 53 scanf("%s",ch+1); 54 n=strlen(ch+1); 55 for(int i=1;i<=n;i++) 56 pam.extend(ch[i]-'a',i); 57 pam.solve(); 58 printf("%lld\n",ans); 59 return 0; 60 }