字符串:回文自动机

类似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
",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
",ans);
59     return 0;
60 }
原文地址:https://www.cnblogs.com/aininot260/p/9636536.html