回文自动机刷题总结
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 }
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 }
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 }
对称的正方形
这题正解不是回文自动机,出这题的时候回文自动机还没怀上呢。。。
二分加二维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 }
以上是关于回文自动机刷题总结的主要内容,如果未能解决你的问题,请参考以下文章