「專題總結」后綴自動機


后綴自動機重點在於性質,東西很多注意區分概念。

  1. 后綴自動機是一個\(DAG\),從根開始的路徑能夠識別\(S\)的每個后綴(子串),一定不存在一條從根開始的路徑能夠識別不是S的子串。

  2. 點:每個節點代表了一個\(endpos\)類,從根到該節點的所有字符串在S中的出現位置相同,
    一個點代表的\(endpos\)集相同的各個串之間有后綴關系且連續,暫且稱這些串的集合為\(P\)

  3. 邊:走\(trans\)相當於在后邊加字符,跳\(parent\)樹則是在前面減字符。

  4. \(nq\)節點是為了划分不同的\(endpos\)集合,有自己的\(len\),但不是\(S\)的某個前綴,不具有\(siz\)

  5. 一個節點的\(endpos\)大小是\(parent\)樹上的實點個數。

  6. 反串的\(parent\)樹上,兩點的\(lcp\)\(lca\)\(len\),注意x y為lca。

  7. 廣義后綴自動機能夠識別多個串的子串。

  8. \(minlen(x)=maxlen(fa[x])+1\),所以按\(len\)排序(桶排),可以得到\(trans\)拓撲序。

  9. 稱一個節點\(x\)能夠代表的字符串為根到x的所有路徑(\(trans\))上的字符排列,則每個節點代表的字符串不重不漏,本質不同。


應用:

1. 求本質不同子串

統計根到其他點的路徑數,或\(Ans=\sum\limits_{i=2}^{tot}len[i]-len[fa[i]]\)

2. 求所有后綴的lcp

建反串的SAM,那么兩個前綴實點的lcp是parent樹上的lca的len,
由於是前綴不需要和\(length\)取min,拓撲統計過每個點(作為lca)的實點點對數。《差異》

3. 字典序最小循環串

復制一倍,建SAM,貪心地從'a'->'z'走\(|S|\)長。《工藝》

4. 每次加入字符,在線求本質不同子串

發現答案的增量只有\(len[np]-len[fa[np]]\),其他點內部守恆。《生成魔咒》

5. 求S和T的最長公共子串

在S的后綴自動機上跑T匹配,若失配則暴力跳fa(由於匹配一位在parent tree上深度至多+1
,跳fa深度一定-1,所以類似棧的勢能復雜度分析, 為\(O(lenth_T)\)),每次得到以i結尾的和S匹配的最長后綴長度\(mx_i\),那么\(Ans=max(mx_i)\)

6. 求多個串的最長公共子串

\(S_1\)建SAM,同上對其余串在SAM上跑匹配,記錄匹配\(mx\)信息在SAM的節點上,
表示該串在這個endpos相同的后綴串集合\(P\)中最多匹配到哪個長度,由於parent上的祖先有該后綴集合中所有串的后綴,
一個節點只要有mx值,就要把其parent樹祖先\(p\)全部置為\(len_p\)。最后答案為在每個SAM節點上(所有串mx值最小值)的最大值。《公共串》

7. 求第K小子串

在DAG上dp出每個節點開始有多少條路徑,從根開始走相當於不斷縮小問題規模,
如果\(k>dp[v]\)則跳過,否則走一步並減去答案串到點v的路徑數。《弦論》
還是想說一下這個DP,如果要求本質不同,當\(rd[u]=0\)時就要++\(dp[u]\),表示無論這個點(這些串)的\(|endpos|\)多大,
我也只算一次,然后“帶着”這個出現的貢獻一直dp到根統計路徑。
如果可以重復,那么就要有\(du[u]\)+=\(|endpos_u|\),位置要算不同,實際上是在根到u的路徑數上乘了\(|endpos_u|\)
同理有\(\sum\limits_{i=2}^{tot}(len[i]-len[fa[i]]) \times |endpos_i|=\frac {n(n+1)}{2}\)

8. T在S中出現次數

在S的SAM上匹配T,如果失配說明S中不存在完整T,否則能找到在SAM上表示T的集合\(P_u\),T的出現次數就為\(|endpos_u|\)
如果要支持在線帶修,需要打棵LCT維護動態parent樹。維護子樹和或者鏈加單點查都行。
注意第二種要給nq點賦同q點值《Substring》


##下面是一些不很模板的應用: ####B. 諸神眷顧的幻想鄉(其實是廣義模板) 求樹上本質不同子串。葉子節點不超過20個,於是可以以每個葉子為根建廣義后綴自動機,~~再加上Deepinc的板子~~。 本題給出了Trie,固定一個根rt,實際上一次dfs建出的SAM,和枚舉葉子節點建出的SAM形態相同。因為q=las的特判。 在線建的復雜度為$\Theta(|A||T|+G(T))$$|A|$為字符集大小,$|T|$為把所有串插入Trie的大小,$G(T)$是Trie上所有葉子深度之和。 DFS在線會被卡成$n^2$?不會證。。。
####H. Cheat 答案具有單調性,考慮二分L。 對M個串建廣義SAM,處理出l[i]為以i結尾的最長匹配后綴長度。不能匹配到L就斷開,因為之后的部分不到L就虧了。 區間划分問題,考慮DP。 設$f[i]$為i之前的最大熟悉長度,有轉移$f[i]=max(f[i-1],f[j]+i-j),i-l[i] \leq j \leq i-L$ 因為$l[i] \geq l[i+1]$,所以$i-l[i] \leq i+1-l[i+1]$ 決策具有單調性,用單調隊列優化下就可以$\Theta(n)$check了。
SAM模板

void extend(int c){
	int p=las,np;np=las=++tot;
	len[np]=len[p]+1;
	for(;p&&!to[p][c];p=fa[p])to[p][c]=np;
	if(!p)fa[np]=1;
	else{
		int q=to[p][c];
		if(len[q]==len[p]+1)fa[np]=q;
		else{
			int nq=++tot;len[nq]=len[p]+1;
			F(i,0,25)to[nq][i]=to[q][i];
			fa[nq]=fa[q];fa[np]=fa[q]=nq;
			for(;p&&to[p][c]==q;p=fa[p])to[p][c]=nq;
		}
	}
}
   
廣義SAM模板

void extend(int x){
	int p=las,q,nq,np;
	if(q=to[p][x]){
		if(len[q]==len[p]+1){las=q;return;}
		las=nq=++tot;len[nq]=len[p]+1;
		F(i,0,c)to[nq][i]=to[q][i];
		fa[nq]=fa[q];fa[q]=nq;
		for(;p&&to[p][x]==q;p=fa[p])to[p][x]=nq;
	}
	else{
		np=las=++tot;
		len[np]=len[p]+1;
		for(;p&&!to[p][x];p=fa[p])to[p][x]=np;
		if(!p)fa[np]=1;
		else{
			q=to[p][x];
			if(len[q]==len[p]+1)fa[np]=q;
			else{
				nq=++tot;
				len[nq]=len[p]+1;
				F(i,0,c)to[nq][i]=to[q][i];
				fa[nq]=fa[q];fa[q]=fa[np]=nq;
				for(;p&&to[p][x]==q;p=fa[p])to[p][x]=nq;
			}
		}
	}
}
   


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM