SPOJ1812 Longest Common Substring II 字尾自動機
阿新 • • 發佈:2019-02-20
題目描述:
求
思路:
對於第一個串建字尾自動機,然後別的串在上面匹配,
匹配的過程和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;
}