模板:回文自动机(PAM)
所謂回文自動(dòng)機(jī),就是關(guān)于回文的自動(dòng)機(jī)。
(逃)
前言
小清新自動(dòng)機(jī)。
經(jīng)歷過(guò)SAM的大風(fēng)大浪,這個(gè)相比而言好理解多了,感覺(jué)也許應(yīng)該先學(xué)這個(gè)再學(xué)SAM…
解析
和trie、AC自動(dòng)機(jī)、SAM等類似的,PAM的每個(gè)結(jié)點(diǎn)表示一個(gè)回文狀態(tài),每條邊對(duì)應(yīng)一條對(duì)應(yīng)字符的轉(zhuǎn)移邊。定義每個(gè)結(jié)點(diǎn)的 fafafa 指針指向其最長(zhǎng)的回文后綴。
和其他自動(dòng)機(jī)有些不同的是,每條轉(zhuǎn)移邊表示的是在父親的狀態(tài)首尾各添加一個(gè)字符(這也是源于回文本身的性質(zhì))(奇根除外),所以每個(gè)結(jié)點(diǎn)的對(duì)應(yīng)最長(zhǎng)后綴長(zhǎng)度為父親長(zhǎng)度 +2。
先給出算法流程:
考慮和SAM一樣用增量法構(gòu)造,假設(shè)目前已經(jīng)建出了 [1,i?1][1,i-1][1,i?1] 的PAM,考慮加入 sis_isi?。
設(shè) si?1s_{i-1}si?1? 對(duì)應(yīng)的結(jié)點(diǎn)位置為 lstlstlst,那么我們就不斷的從 lstlstlst 往上跳 fafafa,直到找到滿足 si?lenp?1=sis_{i-len_{p}-1}=s_isi?lenp??1?=si? 的 ppp 結(jié)點(diǎn)。
此時(shí),如果 ppp 結(jié)點(diǎn)存在 sis_isi? 對(duì)應(yīng)的轉(zhuǎn)移,令 lst←transp,silst\gets trans_{p,s_i}lst←transp,si?? 即可。
否則,新建一個(gè)結(jié)點(diǎn) 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? 即可。
回文串分為奇回文串和偶回文串兩種,而且由于每次長(zhǎng)度+2,奇偶性不變,這兩種串在PAM上無(wú)法互相轉(zhuǎn)化。因此,我們需要分別建一棵奇樹(shù)和偶樹(shù),對(duì)應(yīng)各自的奇根和偶根(分別標(biāo)號(hào)為 1,01,01,0)。
細(xì)節(jié)處理上,需要令 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!
總結(jié)
以上是生活随笔為你收集整理的模板:回文自动机(PAM)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 如何快速打出陌生字电脑如何快速学会打字
- 下一篇: 洛谷P4762: [CERC2014]V