题目链接:点我点我:-)
题目描述:
求
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;
}