POJ.2774.Long Long Message/SPOJ.1811.LCS(后綴自動機)


題目鏈接 POJ2774
SPOJ1811 LCS - Longest Common Substring
確實比后綴數組快多了(廢話→_→)。

\(Description\)

求兩個字符串最長公共子串

\(Solution\)

對串A建立后綴自動機。
A的SAM中包含A的所有子串,且根到每個節點的路徑都是A的子串。如果B(的一部分?)匹配到了SAM上的某個節點,那么這便是AB的公共子串。求出這些點的max(len)即可。
用串B在SAM上逐位匹配,如果匹配,就繼續沿着匹配邊走;
否則,為了匹配當前這位,丟掉B前面一部分,因為fa[p]節點代表的后綴是p所代表后綴的上一個可接受后綴,所以跳fa[p],直到可匹配當前位或到根節點。
注意now的更新方式,如果匹配則+1,否則跳完p后,在p=son[p][c]前用len[p]+1更新now。因為此時p完全匹配了,而len[son[p][c]]是son[p][c]所代表的串的max(len)。(大概是這樣吧。。)

感覺這東西好玄學啊。。

//15064K	79MS
//SPOJ:69M	0.04s
#include <cstdio>
#include <cstring>
#include <algorithm>
const int N=250005<<1;//2n

char s[N>>1];
struct Suffix_Automaton
{
	int las,tot,son[N][26],fa[N],len[N];
	void Insert(int c)
	{
		int p=las,np=++tot; len[las=np]=len[p]+1;
		for(; p&&!son[p][c]; p=fa[p]) son[p][c]=np;
		if(!p) fa[np]=1;
		else
		{
			int q=son[p][c];
			if(len[q]==len[p]+1) fa[np]=q;
			else
			{
				int nq=++tot; len[nq]=len[p]+1;
				memcpy(son[nq],son[q],sizeof son[q]);
				fa[nq]=fa[q], fa[q]=fa[np]=nq;
				for(; son[p][c]==q; p=fa[p]) son[p][c]=nq;
			}
		}
	}
	void Build(char *s)
	{
		las=tot=1;
		for(int i=0,l=strlen(s); i<l; ++i) Insert(s[i]-'a');
	}
	void Query(char *s)
	{
		int ans=0;
		for(int c,now=0,p=1,i=0,l=strlen(s); i<l; ++i,ans=std::max(ans,now))
			if(son[p][c=s[i]-'a']) p=son[p][c], ++now;
			else
			{
				for(; p&&!son[p][c]; p=fa[p]);
				if(!p) p=1, now=0;
				else now=len[p]+1, p=son[p][c];
//			WA:	else p=son[p][c], now=len[p];
			}
		printf("%d",ans);
	}
}sam;

int main()
{
	scanf("%s",s), sam.Build(s);
	scanf("%s",s), sam.Query(s);
	return 0;
}

一些有關后綴自動機的東西:
論文。。
構造:
后綴自動機詳解(感覺這寫的理論好理解)
后綴自動機學習小結(從維護right來寫?)
后綴自動機學習總結(從簡化狀態來寫?)
后綴自動機構造過程演示(這個過程演示很好啊)
后綴自動機的構造(沒看)
題目:
后綴自動機的性質應用
后綴自動機總結
后綴自動機學習小結(應用理論)
幾張SAM的例圖:
aabbab
aabbab
aabb
aabb



免責聲明!

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



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