题意:求n个字符串的最长公共子串。
我们先建出一个串的后缀自动机。
考虑后缀自动机的一个性质就是到当前状态s的所有路径都是互相包含的,这说明了什么呢?我们设Ans[i]是i状态目前能够匹配到的最长长度,那么假设当前串在i匹配的长度是x,那么Ans[i] = min(Ans[i].x),能直接取min就是因为上面的兴致。所以我们现在的目的就是求出所有的Ans[i],再取max就行了。
但是在匹配过程中,假设当前匹配了root->i的路径,那么说明root->parent[i]的路径一定也被匹配到了,但是我们匹配过程中没有更新到这一点,所以每一次匹配完之后逆序更新一下就行了。
#include <iostream> #include <cstring> #include <cstdlib> #include <string> #include <cstdio> #include <algorithm> #include <cmath> #include <ctime> using namespace std; int last = 1,tot = 1,step[200010],son[200010][26],pre[200010]; int num[200010],n,v[200010],val[200010],lent,len,Ans[200010]; int ans = 0; char s[200010],t[200010]; void insert(int x) { int now = last,np = ++ tot; last = tot; step[np] = step[now] + 1; while(son[now][x] == 0 && now != 0) son[now][x] = np,now = pre[now]; if(now == 0) pre[np] = 1; else { int q = son[now][x]; if(step[q] == step[now] + 1) pre[np] = q; else { int nq = ++ tot; step[nq] = step[now] + 1; for(int i = 0;i < 26;i ++) son[nq][i] = son[q][i]; pre[nq] = pre[q]; pre[q] = pre[np] = nq; while(son[now][x] == q) son[now][x] = nq,now = pre[now]; } } } void work() { for(int i = 1;i <= tot;i ++) num[step[i]] ++; for(int i = 1;i <= len;i ++) num[i] += num[i - 1]; for(int i = tot;i > 0;i --) v[num[step[i]] --] = i; } void solve() { memset(val,0,sizeof(val)); int cnt = 0,now = 1; for(int i = 1;i <= lent;i ++) { int x = t[i] - 'a'; while(son[now][x] == 0 && now != 0) now = pre[now]; if(now == 0) now = 1,cnt = 0; else cnt = min(cnt,step[now]) + 1,now = son[now][x]; val[now] = max(val[now],cnt); } for(int i = tot;i >= 1;i --) val[pre[v[i]]] = max(val[pre[v[i]]],val[v[i]]); for(int i = 1;i <= tot;i ++) val[i] = min(val[i],step[i]); for(int i = 1;i <= tot;i ++) Ans[i] = min(Ans[i],val[i]); } int main() { memset(Ans,127,sizeof(Ans)); scanf("%d\n",&n); scanf("%s",s + 1); len = strlen(s + 1); for(int i = 1;i <= len;i ++) insert(s[i] - 'a'); work(); for(int i = 1;i <= n - 1;i ++) { scanf("%s",t + 1); lent = strlen(t + 1); solve(); } for(int i = 2;i <= tot;i ++) if(Ans[i] <= len) ans=max(ans,Ans[i]); printf("%d",ans); return 0; }