1. 程式人生 > >SPOJ1812 Longest Common Substring II 字尾自動機

SPOJ1812 Longest Common Substring II 字尾自動機

題目描述
n(n<=10)個字串的最長公共子串的長度,每個字串長度小於等於105

思路
對於第一個串建字尾自動機,然後別的串在上面匹配,
匹配的過程和SPOJ1811差不多,但是要記下經過的每一個節點的當前匹配的最長長度。
然後,按照拓補序去更新pre的最長長度的值,拓補序就是step值的大小排序,這個應該很好證明
最後記錄所有的串中的對於字尾自動機的每一個節點的匹配最短長度取最大值即可

感想
看了半天題解,還又T又WA,spoj卡時間!
開始並不曉得拓補序的搞法,T慘了!
覺得自己很理解這個演算法了

程式碼

#include<cstdio>
#include<cstdlib> #include<cstring> #include<algorithm> using namespace std; #define Set(a, v) memset(a, v, sizeof(a)) #define For(i, a, b) for(int i = (a); i <= (int)(b); ++i) #define N (10+5) #define SN (200000+5) #define INF 0x3f3f3f3f struct node{ int cnt, id; bool operator
<(const node rhs)const{ return cnt > rhs.cnt; } }tp[SN]; int np, p, q, nq, len, Max, tle; struct Suffix_Automaton{ int root, last, Tot, ch[SN][26], pre[SN], step[SN], nl[SN], ml[SN]; inline void init(){ root = last = ++Tot; Set(ml, INF); } inline
void Insert(char nc){ nc = nc-'a'; np = ++Tot, p = last; step[np] = step[last]+1; last = np; for(;p&&!ch[p][nc]; p = pre[p]) ch[p][nc] = np; if(!p) pre[np] = root; else{ q = ch[p][nc]; if(step[q]==step[p]+1){ pre[np] = q; return; } nq = ++Tot; step[nq] = step[p]+1; pre[nq] = pre[q]; pre[np] = pre[q] = nq; For(i, 0, 25) ch[nq][i] = ch[q][i]; for(;ch[p][nc]==q; p=pre[p]) ch[p][nc] = nq; } } inline void mktp(){ For(i, 1, Tot){tp[i].id = i; tp[i].cnt = ml[i] = step[i];} sort(tp+1, tp+Tot+1); } inline void Find(char *s){ For(i, 1, Tot) nl[i] = 0; len = 0, Max = 0, p = root; char nc; tle = strlen(s)-1; For(i, 0, tle){ nc = s[i]-'a'; if(ch[p][nc]) p = ch[p][nc], nl[p] = max(nl[p], ++len); else{ for(; p&&!ch[p][nc]; p = pre[p]); if(!p) p = root, len = 0; else{ nl[ch[p][nc]] = max(nl[ch[p][nc]], len=step[p]+1); p = ch[p][nc]; } } Max = max(Max, len); } For(i, 1, Tot){ p = tp[i].id; nl[pre[p]] = max(nl[pre[p]], min(step[pre[p]], nl[p])); ml[p] = min(ml[p], nl[p]); } } inline void print(){ int ans = 0; For(i, 1, Tot) ans = max(ans, ml[i]); printf("%d\n", ans); } }sat; char r[SN]; int main(){ #ifndef ONLINE_JUDGE freopen("test.in", "r", stdin); freopen("test.out", "w", stdout); #endif sat.init(); scanf("%s", r); tle = strlen(r)-1; For(i, 0, tle) sat.Insert(r[i]); sat.mktp(); while(scanf("%s", r) != EOF) sat.Find(r); sat.print(); return 0; }