迴文自動機學習筆記

迴文自動機學習筆記

由兩棵子樹構成

  • 一棵節點編號爲0,子樹是長度爲偶數的迴文串
  • 一棵節點編號爲1,子樹是長度爲奇數的迴文串

迴文自動機

奇偶迴文串處理

len[0]=0,len[1]=1len[0] = 0, len[1] = -1使得在11號子樹下的字符串長度1-1

fail[0]=1fail[0] = 1使得字符串最終能跳到1-1,即本身爲迴文串

fail[1]=0fail[1] = 0使得本身爲迴文串的情況,最小真後綴迴文串爲0成立

迴文樹節點

  • 對於00號子樹,路徑上的字母表示迴文串後半段
  • 55號節點爲例,表示的是baab
  • 對於11號子樹,路徑上的字母表示迴文串後半段(包括中間字符)
  • 22號節點爲例,表示的是aa

此圖片爲abbaabbaabbaabba的迴文樹

建樹

in[0]= in[0] = '~',爲必定不相同的字符

fail[]fail[]:表示當前迴文串的最長真後綴迴文串

  • 找到最新節點lastlast
  • 尋找lastlast代表迴文串的前一個點:in[ilen[last]1]in[i - len[last] - 1]
  • 與當前節點(in[i]in[i])比較,若相當於在原迴文串兩邊加上一個字符ch
  • 創建新的節點且len[tree[last][ch]]=len[last]+2len[tree[last][ch]] = len[last] + 2
  • 若當前迴文串不匹配,跳failfail指針尋找最長真後綴迴文子串是否匹配
  • 最終至少會跳到fail[0]==1fail[0] == -1,字符本身必定爲迴文串

failfail指針建立

尋找一個迴文串的最長真後綴迴文子串

相當於尋找lastlast迴文串的最長真後綴迴文子串的匹配迴文串

  • 定義一個新變量jj跳到fail[last]fail[last]
  • 如建樹一樣尋找匹配迴文串即可
  • 對於以自己爲迴文串的迴文串fail[1]=0fail[1] = 0,不然至少找到本身

代碼

in[]in[]:字符串

tree[n][ch]tree[n][ch]:字典樹

fail[]fail[]failfail指針跳轉到當前迴文串的** 最長真後綴迴文串**

len[]len[]:當前迴文串的長度

初始化

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 雙倍迴文

正反向建兩個迴文自動機

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章