模板:回文自动机(PAM)
所謂回文自動機,就是關于回文的自動機。
(逃)
前言
小清新自動機。
經歷過SAM的大風大浪,這個相比而言好理解多了,感覺也許應該先學這個再學SAM…
解析
和trie、AC自動機、SAM等類似的,PAM的每個結點表示一個回文狀態,每條邊對應一條對應字符的轉移邊。定義每個結點的 fafafa 指針指向其最長的回文后綴。
和其他自動機有些不同的是,每條轉移邊表示的是在父親的狀態首尾各添加一個字符(這也是源于回文本身的性質)(奇根除外),所以每個結點的對應最長后綴長度為父親長度 +2。
先給出算法流程:
考慮和SAM一樣用增量法構造,假設目前已經建出了 [1,i?1][1,i-1][1,i?1] 的PAM,考慮加入 sis_isi?。
設 si?1s_{i-1}si?1? 對應的結點位置為 lstlstlst,那么我們就不斷的從 lstlstlst 往上跳 fafafa,直到找到滿足 si?lenp?1=sis_{i-len_{p}-1}=s_isi?lenp??1?=si? 的 ppp 結點。
此時,如果 ppp 結點存在 sis_isi? 對應的轉移,令 lst←transp,silst\gets trans_{p,s_i}lst←transp,si?? 即可。
否則,新建一個結點 curcurcur,令 lencur←lenp+2,transp,si←curlen_{cur}\gets len_{p}+2,trans_{p,s_i}\gets curlencur?←lenp?+2,transp,si??←cur,接著再暴力往上跳 fafafa 尋找 facurfa_{cur}facur? 即可。
回文串分為奇回文串和偶回文串兩種,而且由于每次長度+2,奇偶性不變,這兩種串在PAM上無法互相轉化。因此,我們需要分別建一棵奇樹和偶樹,對應各自的奇根和偶根(分別標號為 1,01,01,0)。
細節處理上,需要令 len1=?1,len0=0,trans1/0,a...z=0,fa1=0,fa0=1len_{1}=-1,len_0=0,trans_{1/0,a...z}=0,fa_{1}=0,fa_0=1len1?=?1,len0?=0,trans1/0,a...z?=0,fa1?=0,fa0?=1。
代碼
int tot=1,lst=1; struct node{int fa,len,num,tr[26]; }st[N]; void init(){st[0].len=0;st[0].fa=1;st[1].len=-1;st[1].fa=0; } int find(int x,int i){//printf(" find:x=%d i=%d ",x,i);while(s[i-st[x].len-1]!=s[i]){x=st[x].fa;} //printf("res=%d\n",x);return x; } void ins(int c,int id){c-='a';lst=find(lst,id);if(!st[lst].tr[c]){int cur=++tot;st[cur].fa=st[find(st[lst].fa,id)].tr[c];st[cur].len=st[lst].len+2;st[lst].tr[c]=cur;st[cur].num=st[st[cur].fa].num+1;}lst=st[lst].tr[c];return; }Thanks for reading!
總結
以上是生活随笔為你收集整理的模板:回文自动机(PAM)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 如何快速打出陌生字电脑如何快速学会打字
- 下一篇: 洛谷P4762: [CERC2014]V