首先你得會manacher,並理解manacher為什麼是對的(不用理解為什麼它是$o(n)$,這個大概記住就好了,不過理解了更方便做$pam$的題)
回文自動機(palindrome automaton),是一類有限狀態自動機,能識別乙個字串的所有回文子串
它可簡化構建出回文樹
網上資料很多,不拿出來一步步說了,說一下陣列意義、放個板子
$len[u]$表示節點$u$代表的回文串的長度
$ch[u][c]$代表在$u$的回文串兩端新增字元$c$得到的新回文串節點
$fail[u]$表示節點$u$的回文串的最長的回文字尾所在的節點
char s[300010];
int n;
//這個板子裡面的num表示當前節點的回文串出現了幾遍
namespace pam
void init()
inline int getfail(int cur,int pos)
void insert(int x)
num[last=ch[cur][c]]++;
}}
fail初始化的時候,如果多組資料並且在newnode裡面初始化資訊,那麼在init的時候記得把fail放到newnode後面
插入的時候函式傳進去的是位置
newnode是len[cur]+2不是+1
首先顯然可以統計這個節點的回文串出現次數
統計次數的時候還要加上$fail$樹上子樹內的所有節點的出現次數
對於一類回文串擁有某個和其$fail$樹有關的性質的題目,可以記錄乙個$trans$,和跳$fail$一樣跳,最後用$bfs$來做$dp$或者遞推
這個問題是問可以把乙個字串分解成最少多少個回文串
解決的方法:
考慮乙個顯然的$dp$:$dp[i]=dp[j-1]+1 (s[i...j]=palindrome)$
記錄乙個$anc[u]$
如果$len[u]-len[fail[u]]==len[fail[u]]-len[fail[fail[u]]]$,那麼$anc[u]=anc[fail[u]]$
否則$anc[u]=u$
對於$u$的所有跳上去的$anc$集合$s$,我們發現,這個集合中的元素構成乙個等差數列,相鄰的兩項差代表一種從當前點前面遞推到當前點的回文串長度
對於每個回文樹節點記錄$tmp[u]=min(tmp[i-len[anc[u]],tmp[fail[u]])$,然後用這個$tmp[u]+1$來更新當前節點的$dp$,然後$u=fail[anc[u]]$往上跳,直到到達根
證明網上有**,這裡放個**
inline void insert(int x)
last=ch[cur][c];
for(cur=ch[cur][c];cur>1;cur=fail[anc[cur]])
}
回文樹(回文自動機) 筆記
回文樹詳解1 what is palindromic auto machine?回文自動機,又叫回文樹,是由俄羅斯人 mikhailrubinchik於2014年夏發明的 這是一種比較新的資料結構,在原文中已有詳細介紹與 實現。回文樹其實不是嚴格的樹形結構,因為它有是兩棵樹,分別是偶數長度的回文樹和...
馬拉車演算法 回文樹(回文自動機)
下標 i 0 是 原字串插入 字元變為 奇數長度,結尾位置新增 維持奇數字元個數 arr字串 經過處理的字串 eg fabbac f a b b a c 輔助陣列p p i 表示 arr字串 在 i 位置的最長回文半徑 兩個關係 最長回文串 是原串 fabbac 的最長回文串長度 p i 1 以 i...
回文自動機
回文自動機,又叫回文樹,是由俄羅斯人 mikhailrubinchik於2014年夏發明的 這是一種比較新的資料結構,在原文中已有詳細介紹與 實現。回文樹其實不是嚴格的樹形結構,因為它有是兩棵樹,分別是偶數長度的回文樹和奇數長度的回文樹,樹中每個節點代表乙個回文串。為了方便,第一棵樹的根是乙個長度為...