泛型之泛型方法
AC 自動機是更高維的 kmp。構造方法感覺更像是運用了 dp 的思想,先對所有模式串建立一棵 Trie 樹,然後考慮某個節點 \(x\),有個 \(w\) 的字尾,考慮如何去求它的 fail 值。於是就有了 AC 自動機的核心程式碼:
int x=q.front(),ff=t[x].fail;q.pop();
for(int i=0;i<26;i++)
if(t[x].nxt[i])t[t[x].nxt[i]].fail=t[ff].nxt[i],q.push(t[x].nxt[i]);
else t[x].nxt[i]=t[ff].nxt[i];
單純匹配的題有 第一塊板子。
比較無腦的就是可以在 AC 自動機上 DP,和在 kmp 自動機上 DP 是同一個道理。
一般的題目都會用到 fail 樹的性質。自動機上每個點往 fail 對應的點上連邊,顯然最後會形成一棵樹(每個點只會往更淺的點連線)。有一個顯然的性質是,對於一個節點 \(x\),它到根的路徑可以看成是 kmp 的一個匹配過程,所以實際上這些點的串都是 \(x\)
fail 樹也是樹,所以可以樹剖,這牽扯到一個性質。首先根據字典樹的原理,一個節點在字典樹上到根的所有節點形成了它的字首集合,而一個串在另一箇中出現可以看成前者是後者字首的字尾。而前面也說了,\(A\) 是 \(B\) 字尾表現為在 fail 樹上 \(B\) 是 \(A\) 子樹中的節點,所以要統計一個串在另一個串中出現了幾次,就只需要把後者到根(字典樹上)的所有點標記一下,然後查詢前者子樹中有多少個標記節點即可,用樹狀陣列可以維護。