迴文自動機學習筆記
由兩棵子樹構成
- 一棵節點編號爲0,子樹是長度爲偶數的迴文串
- 一棵節點編號爲1,子樹是長度爲奇數的迴文串
迴文自動機
奇偶迴文串處理
使得在號子樹下的字符串長度
使得字符串最終能跳到,即本身爲迴文串
使得本身爲迴文串的情況,最小真後綴迴文串爲0成立
迴文樹節點
- 對於號子樹,路徑上的字母表示迴文串後半段
- 以號節點爲例,表示的是
baab
- 對於號子樹,路徑上的字母表示迴文串後半段(包括中間字符)
- 以號節點爲例,表示的是
此圖片爲的迴文樹
建樹
,爲必定不相同的字符
:表示當前迴文串的最長真後綴迴文串
- 找到最新節點,
- 尋找代表迴文串的前一個點:
- 與當前節點()比較,若相當於在原迴文串兩邊加上一個字符
ch
- 創建新的節點且
- 若當前迴文串不匹配,跳指針尋找最長真後綴迴文子串是否匹配
- 最終至少會跳到,字符本身必定爲迴文串
指針建立
尋找一個迴文串的最長真後綴迴文子串
相當於尋找迴文串的最長真後綴迴文子串的匹配迴文串
- 定義一個新變量跳到
- 如建樹一樣尋找匹配迴文串即可
- 對於以自己爲迴文串的迴文串,不然至少找到本身
代碼
:字符串
:字典樹
:指針跳轉到當前迴文串的** 最長真後綴迴文串**
:當前迴文串的長度
初始化
scanf("%s", in + 1); in[0] = '#';
//第一個爲不同字符
fail[0] = 1; fail[1] = 0;
//保證最終跳到本身
len[0] = 0; len[1] = -1;
//易處理處理
last = 0;
//last最新節點置0
num = 1;
//字典樹編號,已有2個節點:0,1
建樹
for (int i = 1; i <= n; i++) {
while (in[i - len[last] - 1] != in[i]) last = fail[last];
//跳到第一個匹配的串
if (!tree[last][in[i] - 'a']) {//若改字符串不存在
len[++num] = len[last] + 2;//新的迴文串爲原迴文串+2
int j = fail[last];//當前串的最長真後綴迴文串
while (in[i - len[j] - 1] != in[i]) j = fail[j];
//最長真後綴迴文串的第一個匹配串
fail[num] = tree[j][in[i] - 'a'];
tree[last][in[i] - 'a'] = num;
//字典樹編號
}
last = tree[last][in[i] - 'a'];
//更新last
}
模板題
P5496 迴文自動機(PAM)
P4287 雙倍迴文
正反向建兩個迴文自動機