【學習筆記】迴文自動機
阿新 • • 發佈:2019-01-04
依舊是後面再補上講解吧希望我不要忘記惹。。。。
本質是一顆trie,節點代表了迴文的一半;
自動機節點維護長度和最大回文字尾的fail指標;
奇數迴文的根長度為-1,編號1,偶數0,1;(編號是有藝術的)
插入沿著上一個點找是否有匹配的迴文;
注意如果要新建節點的話應該再找新建點的fail,繼續想上跳即可找到,此時要先找fail再連新建點,不然在新建點的父親為1的時候會出錯;
-
習題:
- bzoj2565最長雙迴文串
- 用迴文自動機正反兩邊跑出每個點的前後最長迴文串,列舉斷點統記ans
-
1 #include<bits/stdc++.h> 2 #define rg register 3 #define il inline 4 using namespace std; 5 const int N=100010; 6 char s[N]; 7 int n,sz,fl[N],len[N],ch[N][26],l[N],r[N]; 8 il int find(int x,int y){ 9 return s[y]==s[y-len[x]-1]?x:find(fl[x],y); 10 } 11 void cal(){
bzoj2565 - bzoj3676[Apio2014]迴文串
- 迴文自動機裡節點儲存狀態是本質不同的迴文串;
- 記錄每個節點更新的次數$cnt[]$ , 一個節點出現同時代表其fail祖先都出現,所以$cnt[ fl[i] ] += cnt[i]$;
- 有個技巧:迴文自動機的拓撲序即編號序列;
1 #include<bits/stdc++.h> 2 #define rg register 3 #define il inline 4 #define Run(i,l,r) for(rg int i=l;i<=r;i++) 5 #define Don(i,l,r) for(rg int i=l;i<=r;i++) 6 #define ll long long 7 using namespace std; 8 const int N=300100; 9 int n,fl[N],ch[N][26],tot,len[N],sz; 10 ll cnt[N]; 11 char s[N]; 12 inline int find(int x,int y){ 13 while(1){ 14 if(s[x - len[y] - 1] == s[ x ])break; 15 y = fl[ y ]; 16 } 17 return y; 18 } 19 int main(){ 20 freopen( "bzoj3676.in" , "r" , stdin); 21 freopen( "bzoj3676.out", "w", stdout); 22 scanf("%s",s+1); 23 sz=1; 24 fl[0]=fl[1]=1; 25 len[0]=0;len[1]=-1; 26 int now = 0 ; 27 s[0] = -1; 28 for(n=1 ; s[ n ] ; n++){ 29 s[ n ] -= 'a' ; 30 now = find( n , now ); 31 if(! ch[ now ][ s[n] ]){ 32 len[ ++sz ] = len[now] + 2; 33 int tmp = find( n , fl[ now ] ); 34 fl[ sz ] = ch[ tmp ][ s[n] ]; 35 ch[ now ][ s[n] ] = sz ; 36 } 37 cnt[ now = ch[ now ][ s[n] ] ] ++; 38 } 39 ll ans = 0; 40 for( int i = sz; i > 1 ; --i){ 41 cnt[ fl[i] ] += cnt[ i ]; 42 ans = max(ans , cnt[i] * len[i] ); 43 } 44 cout << ans << endl; 45 return 0; 46 }
bzoj3676 - bzoj4480[Jsoi2013]快樂的jyy
- 迴文串出現次數的乘積的和的話。。。
- 先對$A$串做迴文自動機,然後$hash$存下每個迴文串出現次數
- 然後對$B$串再做一次統計答案
- $hash$注意區分奇偶,同時每位最小值不要出現0 ,$fxy$說常見模數+底$26$是被卡了的($推薦2333333$)
1 #include<cstdio> 2 #include<iostream> 3 #include<map> 4 #include<cstring> 5 #define rg register 6 #define il inline 7 #define ull unsigned long long 8 #define ll long long 9 #define base 233 10 using namespace std; 11 const int N=50010; 12 ull h[N]; 13 char s[N]; 14 ll cnt[N],ans; 15 int n,sz,fl[N],ch[N][26],len[N],db[N]; 16 map<ull,ll>mp; 17 il int newd(int d){ 18 len[sz]=d; 19 fl[sz]=cnt[sz]=h[sz]=0; 20 memset(ch[sz],0,sizeof(ch[sz])); 21 return sz++; 22 } 23 void init(){ 24 s[0]=-1; 25 sz=0; 26 newd(0);newd(-1); 27 fl[0]=fl[1]=1; 28 h[0]=0;h[1]=-1; 29 } 30 il int find(int x,int y){return s[x]==s[x-len[y]-1]?y:find(x,fl[y]);} 31 void solve(int fg){ 32 init(); 33 int l = strlen(s+1); 34 for(rg int i=1,now=0;i<=l;i++){ 35 now = find(i,now); 36 if(!ch[now][s[i]-'A']){ 37 fl[newd(len[now]+2)]=ch[find(i,fl[now])][s[i]-'A']; 38 ch[now][s[i]-'A']=sz-1; 39 h[sz-1]=h[now]*base+s[i]; 40 } 41 now = ch[now][s[i]-'A']; 42 cnt[now]++; 43 db[i] = len[now]; 44 } 45 for(rg int i=sz-1;i>=2;i--)if(!fg){ 46 cnt[fl[i]]+=cnt[i]; 47 mp[h[i]] = cnt[i]; 48 }else{ 49 cnt[fl[i]]+=cnt[i]; 50 ans += mp[h[i]] * cnt[i]; 51 } 52 } 53 int main(){ 54 freopen("bzoj4480.in","r",stdin); 55 freopen("bzoj4480.out","w",stdout); 56 scanf("%s",s+1);solve(0); 57 scanf("%s",s+1);solve(1); 58 printf("%lld\n",ans); 59 return 0; 60 }
bzoj4480