A string is finite sequence of characters over a non-empty finite set Σ.
In this problem, Σ is the set of lowercase letters.
Substring, also called factor, is a consecutive sequence of characters occurrences at least once in a string.
Now your task is a bit harder, for some given strings, find the length of the longest common substring of them.
Here common substring means a substring of two or more strings.
Input
The input contains at most 10 lines, each line consists of no more than 100000 lowercase letters, representing a string.
Output
The length of the longest common substring. If such string doesn't exist, print "0" instead.
Example
Input: alsdfkjfjkdsal fdjskalajfkdsla aaaajfaaaa Output: 2
Notice: new testcases added
两个月前留下的万年老坑终于填了……
题目大意很简单,求10个串的最长公共子串,长度范围1e5。
由于数据范围比较容易想到后缀自动机。我们可以先对第一个字符串建立一个后缀自动机,用后面的每一个串跑。记录下每一个节点的最大匹配长度mx[i]。每一次跑完过后更新对于所有串跑出来每一个节点mx结果的最小值mn。最后在所有点的mn值中选取最大的即可。
需要注意的是,因为儿子节点的更新会让父亲节点的值改变,所以跑完一遍后缀自动机要按拓扑序向上更新父亲的mx值。而求一个后缀自动机的拓扑序很简单,就是所有节点按len值排序就行了(后缀自动机的性质)。所以我们可以基数排序一遍,得到拓扑序。渣渣常数的代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn = 2e5 + 20;
int trie[maxn][26], len[maxn], fa[maxn], dp[maxn], tdp[maxn], num[maxn], last, cnt, top[maxn];
char s[maxn], ms[maxn];
void add(int x) {
int id = s[x] - 'a';
int np = ++cnt, p = last;
last = np;
len[np] = tdp[np] = x + 1;
while(p && !trie[p][id]) {
trie[p][id] = np;
p = fa[p];
}
if(p == 0) fa[np] = 1;
else {
int q = trie[p][id];
if(len[p] + 1 == len[q]) fa[np] = q;
else {
int lca = ++cnt;
len[lca] = tdp[lca] = len[p] + 1;
fa[lca] = fa[q];
fa[q] = fa[np] = lca;
memcpy(trie[lca], trie[q], sizeof(trie[q]));
while(p && trie[p][id] == q) {
trie[p][id] = lca;
p = fa[p];
}
}
}
}
void work() {
int p = 1, step = 0;
int l = strlen(ms);
for(register int i = 0; i < l; ++i) {
int id = ms[i] - 'a';
if(trie[p][id]) ++step, p = trie[p][id];
else {
while(p && !trie[p][id]) p = fa[p];
if(!p) p = 1, step = 0;
else step = len[p] + 1, p = trie[p][id];
}
if(dp[p] < step) dp[p] = step;
}
for(register int i = cnt; i; --i) {
p = top[i];
if(dp[p] < tdp[p]) tdp[p] = dp[p];
if(fa[p] && dp[fa[p]] < dp[p]) dp[fa[p]] = dp[p];
dp[p]=0;
}
}
int main() {
last = cnt = 1;
int mx = 0;
scanf("%s", s);
int l = strlen(s);
for(register int i = 0; i < l; ++i) add(i);
for(register int i = 1; i <= cnt; ++i) ++num[len[i]];
for(register int i = 1; i <= l; ++i) num[i] += num[i - 1];
for(register int i = 1; i <= cnt; ++i) top[num[len[i]]--] = i;
while(~scanf("%s", ms)) work();
for(register int i = 1; i <= cnt; ++i)
if(mx < tdp[i]) mx = tdp[i];
printf("%d", mx);
return 0;
}
rockdu
没有帐号? 立即注册