回文自动机刷题总结

Posted loadingkkk

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了回文自动机刷题总结相关的知识,希望对你有一定的参考价值。

最长双回文串

裸的回文自动机,将串reverse再插入一遍即可。

双倍回文

这题可以只维护偶回文串然后疯狂加特判判掉奇串

回文自动机,再多维护一个trans指针,指向trans[x]表示长度小于len[x]/2的最长的回文后缀

trans指针可以从父亲(不是fail)的trans指针求出。

其实还可以直接建完自动机后在fail树(即把fail指针当作父亲边构成的树)上开桶dfs

技术图片
 1 #include<bits/stdc++.h>
 2 #define N 500050
 3 using namespace std;
 4 int n;
 5 char s[N];
 6 struct PAM{
 7     int tot,las;
 8     struct node{int len,fail,trans,ch[26];}tr[N];
 9     PAM(){tr[0].fail=-1;}
10     inline int extend(int n){
11         int c=s[n]-a,p=las;
12     //    cout<<tr[p].len<<endl;
13         while((~p)&&s[n-tr[p].len-1]!=s[n])p=tr[p].fail;
14     //    cout<<n<<"-> "<<p<<endl;
15         if(p==-1){las=0;return 0;}
16         if(!tr[p].ch[c]){
17             int np=++tot,k=tr[p].fail;
18             tr[np].len=tr[p].len+2;
19             while((~k)&&s[n-tr[k].len-1]!=s[n])k=tr[k].fail;
20             if(~k){
21                 tr[np].fail=tr[k].ch[c];
22                 if(tr[np].len>2){
23                     k=tr[p].trans;
24                     while((~k)&&(s[n-tr[k].len-1]!=s[n]||tr[k].len+2>(tr[np].len>>1)))
25                         k=tr[k].fail;
26         //            cout<<np<<" "<<k<<endl;
27                     if(~k)tr[np].trans=tr[k].ch[c];
28                 }
29             }tr[p].ch[c]=np;
30         }
31         las=tr[p].ch[c];
32     //    cout<<n<<" "<<las<<" "<<tr[las].len<<" "<<tr[las].trans<<" "<<tr[tr[las].trans].len<<endl;
33         return tr[tr[las].trans].len==(tr[las].len>>1)?tr[las].len:0;
34     }
35 }t1;
36 int main(){
37     scanf("%d%s",&n,s+1);
38     int ans=0;
39     for(int i=1,x;i<=n;++i)
40         x=t1.extend(i),ans=max(ans,x);
41     cout<<ans<<endl;
42     return 0;
43 }
View Code

Antisymmetry

题意转化一下,可以用回文自动机。

在插入一个点后,立马把它取反,然后自动机正常建即可。

额,好像不能正常建,只建偶回文串

然后倒扫一遍自动机的节点统计答案,并累加贡献即可。

技术图片
 1 #include<bits/stdc++.h>
 2 #define N 500050
 3 #define int long long
 4 using namespace std;
 5 int n;
 6 char s[N];
 7 struct PAM{
 8     int las,tot;
 9     struct node{
10         int len,sz,fail,ch[2];
11     }tr[N];
12     PAM(){tr[0].fail=-1;}
13     inline void extend(int n){
14         int p=las,c=s[n]-0;
15         while((~p)&&s[n-tr[p].len-1]!=s[n])p=tr[p].fail;
16         if(!(~p)){las=0;return;}
17 //        printf("%d %d
",n,p);
18         if(!tr[p].ch[c]){
19             int np=++tot,k=tr[p].fail;
20             tr[np].len=tr[p].len+2;
21             while((~k)&&s[n-tr[k].len-1]!=s[n])k=tr[k].fail;
22             if(k!=-1)tr[np].fail=tr[k].ch[c];
23             tr[p].ch[c]=np;
24         }
25         las=tr[p].ch[c];++tr[las].sz;
26 //        printf("las:%d len:%d fail:%d
",las,tr[las].len,tr[las].fail);
27     }
28     inline int getans(){
29         int ret=0;
30 //        cout<<tot<<endl;
31         for(int i=tot;i;--i){
32 //            printf("i:%d len:%d sz:%d
",i,tr[i].len,tr[i].sz);
33             if(!(tr[i].len&1))ret+=tr[i].sz;
34             tr[tr[i].fail].sz+=tr[i].sz;
35         }
36         return ret;
37     }
38 }t1;
39  main(){
40     scanf("%lld%s",&n,s+1);
41     for(int i=1;i<=n;++i){
42         t1.extend(i);
43         s[i]=s[i]==0?1:0;
44     }
45 //    printf("%s
",s+1);
46     printf("%lld
",t1.getans());
47     return 0;
48 }
View Code

I Love Palindrome String

和双倍回文类似。在最后的fail树上开桶dfs统计答案,在回溯时累加贡献。

技术图片
 1 #include<iostream>
 2 #include<cstdio>
 3 #include<cstring>
 4 #include<algorithm>
 5 #define N 300050
 6 using namespace std;
 7 int n;char s[N];
 8 int ans[N],t[N];
 9 struct PAM{
10     int las,tot;
11     int he[N],ne[N<<1],to[N<<1],bk[N],cnt,ans[N];
12     struct node{
13         int ch[26],sz,len,fail;
14         inline void clear(){
15             memset(ch,0,sizeof(ch));
16             sz=len=fail=0;
17         }
18     }tr[N];
19     inline void add(int x,int y){
20         to[++cnt]=y;ne[cnt]=he[x];he[x]=cnt;
21     }
22     inline void init(){
23         memset(he,0,sizeof(int)*(n+1));
24         memset(ans,0,sizeof(int)*(n+1));
25         cnt=tot=las=0;
26         tr[0].clear();tr[1].clear();
27         tr[tot=1].len=-1;tr[0].fail=1;
28         add(1,0);
29     }
30     inline void extend(int n){
31         int c=s[n]-a,p=las;
32         while(s[n-tr[p].len-1]!=s[n])p=tr[p].fail;
33         if(!tr[p].ch[c]){
34             int np=++tot,k=tr[p].fail;tr[np].clear();
35             tr[np].len=tr[p].len+2;
36             while(s[n-tr[k].len-1]!=s[n])k=tr[k].fail;
37             tr[np].fail=tr[k].ch[c];
38             add(tr[k].ch[c],np);
39             tr[p].ch[c]=np;
40         }
41         las=tr[p].ch[c];++tr[las].sz;
42     //    printf("n:%d las:%d len:%d sz:%d fail:%d
",n,las,tr[las].len,tr[las].sz,tr[las].fail);
43     }
44     inline void dfs(int g){
45     //    printf("g:%d sz:%d len:%d fail:%d
",g,tr[g].sz,tr[g].len,tr[g].fail);
46         if(tr[g].len>0)++bk[tr[g].len];
47         for(int i=he[g];i;i=ne[i]){
48             dfs(to[i]);
49             tr[g].sz+=tr[to[i]].sz;
50         }
51         if(bk[tr[g].len+1>>1]&&tr[g].len>0)ans[tr[g].len]+=tr[g].sz;
52         if(tr[g].len>0)--bk[tr[g].len];
53     }
54     inline void pr(){
55         for(int i=1;i<n;++i)printf("%d ",ans[i]);
56         printf("%d
",ans[n]);
57     }
58 }t1;
59 int main(){
60     if(scanf("%s",s+1)==EOF)return 0;
61     t1.init();n=strlen(s+1);
62     for(int i=1;i<=n;++i)t1.extend(i);
63     t1.dfs(1);
64     t1.pr();
65     return main();
66 }
View Code

对称的正方形

这题正解不是回文自动机,出这题的时候回文自动机还没怀上呢。。

二分加二维hash

技术图片
 1 #include<bits/stdc++.h>
 2 #define N 1010
 3 #define ull unsigned long long
 4 using namespace std;
 5 inline int read(){
 6     int s=0;char c=getchar();
 7     while(c>9||c<0)c=getchar();
 8     while(c>=0&&c<=9)s=s*10+c-0,c=getchar();
 9     return s;
10 }
11 int n,m,ans;
12 ull a[N][N];
13 const ull P1=1000000007,P2=13331;
14 ull po1[N],po2[N];
15 inline void to(int &t1,int &t2,int tag){
16     if(tag&1)t1=n-t1+1;
17     if(tag&2)t2=m-t2+1;
18 }
19 inline void init(int n){
20     po1[0]=po2[0]=1;
21     for(int i=1;i<=n;++i)po1[i]=po1[i-1]*P1,po2[i]=po2[i-1]*P2;
22 }
23 struct HASH{
24     ull ha[N][N],now;
25     inline void init(int tag){
26         for(int i=1;i<=n;++i){
27             for(int j=1,x,y;j<=m;++j){
28                 x=i,y=j;
29                 to(x,y,tag);
30                 ha[i][j]=ha[i-1][j]*P1+(ha[i][j-1]-ha[i-1][j-1]*P1)*P2+a[x][y];
31             }
32         }
33     }
34     inline void check(int x,int y,int len,int tag){
35         to(x,y,tag);
36         now=ha[x][y]
37             -ha[x-len][y]*po1[len]
38             -ha[x][y-len]*po2[len]
39             +ha[x-len][y-len]*po1[len]*po2[len];
40     }
41 }H[4];
42 int main(){
43     scanf("%d%d",&n,&m);
44     for(int i=1;i<=n;++i)
45         for(int j=1;j<=m;++j)
46             a[i][j]=read();
47     init(max(n,m));
48     for(int i=0;i<=3;++i)H[i].init(i);
49     for(int i=1;i<=n;++i){
50         for(int j=1,l,r;j<=m;++j){
51             r=min(j,m-j);r=min(r,i);r=min(r,n-i);++r;l=0;
52         //    printf("%d %d %d %d
",i,j,l,r);
53             while(l+1<r){
54                 int mid=l+r>>1;
55                 H[0].check(i,j,mid,0);
56                 H[1].check(i+1,j,mid,1);
57                 H[2].check(i,j+1,mid,2);
58                 H[3].check(i+1,j+1,mid,3);
59                 if(H[0].now==H[1].now&&H[1].now==H[2].now&&H[2].now==H[3].now)l=mid;
60                 else r=mid;
61         //        if(i==1&&j==3)
62         //        printf("%llu %llu %llu %llu
",H[0].now,H[1].now,H[2].now,H[3].now);
63             }
64             ans+=l;
65             r=min(j,m-j+1);r=min(r,i);r=min(r,n-i+1);l=1;++r;
66             while(l+1<r){
67                 int mid=l+r>>1;
68                 H[0].check(i,j,mid,0);
69                 H[1].check(i,j,mid,1);
70                 H[2].check(i,j,mid,2);
71                 H[3].check(i,j,mid,3);
72                 if(H[0].now==H[1].now&&H[1].now==H[2].now&&H[2].now==H[3].now)l=mid;
73                 else r=mid;
74             }
75             ans+=l;
76         }
77     }
78     cout<<ans<<endl;
79     return 0;
80 }
View Code

以上是关于回文自动机刷题总结的主要内容,如果未能解决你的问题,请参考以下文章

leetcode之动态规划刷题总结1(Java)

刷题日记最长回文子串

刷题日记最长回文子串

刷题日记最长回文子串

leetcode之动态规划刷题总结4

java刷题--647回文子串