1. 程式人生 > 其它 >迴文自動機(PAM)學習小記

迴文自動機(PAM)學習小記

迴文自動機(PAM)

迴文樹


1.迴文樹上每一個節點代表了原串上出現過的一個本質不同迴文子串,原串上的每一個迴文子串都在迴文樹上有對應。迴文樹上每一個點代表的串都是迴文串。

2.迴文樹分兩部分,奇和偶,奇樹上的點代表的迴文串長度為奇數,偶樹上的為偶樹

3.兒子節點代表串長度為父親節點代表串長度+2

4.和\(Trie\)相似的其他性質,在迴文樹中,父親與兒子的連邊上的字母代表了往父親迴文串首尾加上這個字母形成兒子所代表的迴文串。

Fail指標


學過AC自動機的OIer們應該就很熟悉啦QwQ

\(Fail\)指標含義:這個節點所代表的迴文串的最長迴文字尾

Trans指標


一般做許多\(PAM\)題目常用的東西

\(Trans\)

指標含義:小於等於當前節點長度一半的最長迴文字尾

struct PAM {
	int cnt;
	int len[100001], num[100001], fail[100001], tree[100001][27], fa[100001], trans[100001];
	void clear() {
		memset(len, 0, sizeof(len));
		memset(num, 0, sizeof(num));
		memset(fail, 0, sizeof(fail));
		memset(tree, 0, sizeof(tree));
		memset(fa, 0, sizeof(fa));
		memset(trans, 0, sizeof(trans));
		cnt = 1;
		fail[0] = 1;//跳到奇根上,即奇數迴文串
		len[1] = -1;//使得一開始的長度為1
	}
	int getFail(int p, int i) {
		while (tmp[i - len[p] - 1] != tmp[i] || i - len[p] - 1 < 0)//不斷地跳最長的迴文字尾
			p = fail[p];
		return p;
	}
	int getTrans(int p, int i) {
		while (tmp[i - len[p] - 1] != tmp[i] || (len[p] + 2 << 1) > len[cnt])//類似fail,只是長度要求
			p = fail[p];
		return p;		
	}
	void insert(int u, int i) {
		int Fail = getFail(last, i);
		if (!tree[Fail][u]) {//類似Trie操作
			len[++cnt] = len[Fail] + 2;
			fail[cnt] = tree[getFail(fail[Fail], i)][u];//次短最長迴文字尾
			tree[Fail][u] = cnt;
			num[cnt] = num[fail[cnt]] + 1;
			fa[cnt] = Fail;
			if (len[cnt] <= 2)
				trans[cnt] = fail[cnt];//特判
			else
				trans[cnt] = tree[getTrans(trans[Fail], i)][u];
		}
		last = tree[Fail][u];
	}
};