字尾自動機

2021-08-16 23:54:07 字數 1798 閱讀 4930

常用於處理字串問題,可以高效解決許多字串問題。

有點像將乙個字串的所有字尾都建在乙個ac自動機上,但不同的是字尾自動機的節點數最多為2*n,因為它只記錄需要記錄的點,一些沒有記錄東西的點可以視為與下面有價值的節點並在一起,這樣大大降低了時間複雜度和空間複雜度。

對於每乙個節點記錄它的後面加上每個字元後字尾最長可以到達的節點,以及它的長度len,它去掉乙個最短字首後存在的節點pre。

對於加入乙個字元c,首先新開乙個np,其長度為last節點的長度+1(上一次加入,此時長度最長的節點),然後沿著last節點的pre向上查詢,直到根節點或是在該節點(命名為p)後面加上c後能匹配到節點q。

若為前者,則np的pre為根節點。

若為後者,則判斷q的len是否為p的len+1。

如果是,說明q節點是與p直接相連的,而不是被合併在q節點的。

反之,則說明該節點被省略,新建節點nq,複製q點除了長度外的所有資訊,nq的長度為p的長度+1,而q,np的pre都改為nq,接著沿著p的pre向上找,直到它在後面加上c後匹配到的節點不是q停止,將這些原來匹配到q的節點都改為加上c後匹配到nq.

void add(char v)

q=node[p].to[u];

if(node[q].len==node[p].len+1)

nq=++tt;

memcpy(node[nq].to,node[q].to,sizeof(node[q].to));

node[nq].pre=node[q].pre

; node[nq].len=node[p].len+1

; node[q].pre=node[np].pre=nq;

for(; p!=-1&&node[p].to[u]==q; p=node[p].pre)

node[p].to[u]=nq;

}

此題也可以用高度陣列來做,複雜度為o(n*(logn)^2),而字尾自動機要快的多,複雜度僅為o(n).

求兩個字串的最長公共子串。

首先對a串建字尾自動機,之後b串沿著字尾自動機匹配,匹配到乙個答案加一,失敗則沿著該節點的pre向上找,直到匹配上或是找到了根節點,答案改為此時節點的長度,匹配過程中的答案最大值即為最長公共子串行的長度。

#include#include#include#include

#include#define n 20010

using namespace std;

int t,last,tt,ans;

string a,b;

struct node

void init()

} node[20010];

inline int zh(char u)

void add(char v)

q=node[p].to[u];

if(node[q].len==node[p].len+1)

nq=++tt;

memcpy(node[nq].to,node[q].to,sizeof(node[q].to));

node[nq].pre=node[q].pre;

node[nq].len=node[p].len+1;

node[q].pre=node[np].pre=nq;

for(; p!=-1&&node[p].to[u]==q; p=node[p].pre)

node[p].to[u]=nq;

}void find()

ans=max(ans,res);

}}int main()

}

字尾自動機

基礎知識 step i 表示的是字串i在原字串中的位置。pareint i 表示root到parent i 的子串是root到i的最長字尾。字尾自動機遍歷可以得到原字串的所有子串。特殊技巧 一 字尾自動機的不同子串數有兩種求法 1.ans step i step parent i 1 i cnt 2...

字尾自動機

基礎學習 簡潔明瞭的講解 總狀態數不超過2n 12n 1 2n 1 包括初始狀態 統計每個end po sendpos endpos 等價類出現位置數量時,要按長度從長到短的計算cnt cntcn t。那為什麼一定要從長到短呢?比如回文自動機就直接是按照節點編號從大到小計算cnt cntcn t 罪...

字尾自動機

include include includeusing namespace std const int n 1000000 10 char s n int len 2 n tr 2 n 32 link 2 n con 2,last 1 void add int c int main return ...