题目链接:https://cn.vjudge.net/problem/SPOJ-LCS2
题解:求两个串的:https://blog.csdn.net/mmk27_word/article/details/98614115,dp[i]表示到 i 这个节点,匹配最长的公共长度,两个串的时候因为只匹配一次,所以我们取个最大值即可,如果多个的话,因为你不知道后面匹配的是哪个节点位置,所以要把每个节点的fa也要更新一下,每个节点取个最小值,最后取个最大值即可
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 250010;
int X[N << 1], Y[N << 1];
int cntans[N << 1], dp[N << 1];
struct SAM {
int n; // 字符串长度
int tot; // 节点编号
int len[N << 1]; // 最长子串的长度 (该节点子串数量 = len[x] - len[fa[x]])
int fa[N << 1]; // // 后缀链接 (最短串前部少一个字符所到达的状态)
int cnt[N << 1]; // 被后缀链接的个数,方便求节点字符串的个数
int nex[N << 1][26]; // 下一个状态
int last; // 最后一个节点
ll num[N << 1]; // 该状态子串的数量
ll maxx[N << 1]; // 长度为x的子串出现次数最多的子串的数目
ll sum[N << 1]; // 该节点后面所形成的自字符串的总数
ll ans; // 不同字符串数目
ll sublen; // 不同字符串总长度
void init(int x) {
for(int i = 0; i <= x * 2 + 10; i++) {
maxx[i] = 0;
cnt[i] = 0;
num[i] = 0;
for(int j = 0; j <= 25; j++)
nex[i][j] = 0;
}
n = 0;
last = 1;
tot = 1; // 1是起始点 空集
fa[1] = 0;
len[1] = 0;
}
void insert (int c) {
n++;
int x = ++tot; // 新建节点
len[x] = len[last] + 1;
num[x] = 1;
int p;
for(p = last; p && !nex[p][c]; p = fa[p]) nex[p][c] = x; //沿着后缀连接 将所有没有字符c转移的节点直接指向新节点
if(!p) fa[x] = 1, cnt[1]++; // 没有c的转移,直接链接到起点
else {
int q = nex[p][c];
if(len[p] + 1 == len[q]) // p q连续
fa[x] = q, cnt[q]++;
else {
int nq = ++tot; // 不连续 复制一份q的 使得和p连续
len[nq] = len[p] + 1;
fa[nq] = fa[q];
memcpy(nex[nq], nex[q], sizeof(nex[q]));
for(; p && nex[p][c] == q; p = fa[p]) nex[p][c] = nq; //沿着后缀连接 将所有通过c转移为q的改为nq
fa[q] = fa[x] = nq;
cnt[nq] += 2;
}
}
last = x;
}
void getposnum() { // 每个节点子串出现的次数
queue<int> q;
int x;
for(int i = 1; i <= tot; i++)
if(!cnt[i])
q.push(i);
while(!q.empty()) {
x = q.front(); q.pop();
num[fa[x]] += num[x];
if(--cnt[fa[x]] == 0) q.push(fa[x]);
}
}
void getSUM() {
for(int i = tot; i >= 1; i--) {
sum[i] = num[i];
for(int j = 0; j <= 25; j++)
sum[i] += sum[nex[i][j]];
// cout << i << " " << sum[i] << endl;
}
}
void getsubnum() { // 不同字符串数目
ans = 0;
for(int i = 1; i <= tot; i++)
ans += len[i] - len[fa[i]];
}
void getmaxx() { // 长度为x的子串出现次数最多的子串的数目
// getposnum();
for(int i = 1; i <= tot; i++) maxx[len[i]] = max(maxx[len[i]], num[i]);
for(int i = n - 1; i >= 1; i--) maxx[i] = max(maxx[i], maxx[i + 1]);
}
/*这也是计算节点子串出现次数的方法
void count() {
memset(X,0,sizeof(X));
for(int i=1;i<=tot;i++) X[len[i]]++;
for(int i=1;i<=tot;i++) X[i]+=X[i-1];
for(int i=1;i<=tot;i++) Y[X[len[i]]--]=i;
for(int i=tot;i>=1;i--) num[fa[Y[i]]]+=num[Y[i]];
for(int i = tot;i >= 1; i--) {
sum[Y[i]] = 1;
for(int j = 0 ;j < 25; j++)
sum[Y[i]] += ans[nex[Y[i]][j]];
}
}
*/
void getsublen() {
sublen = 0;
for(int i = 1; i <= tot; i++) {
sublen += 1LL * (len[i] + len[fa[i]] + 1) * (len[i] - len[fa[i]]) / 2;
}
// cout << sublen << endl;
}
int compare(char str[]) {
int l = strlen(str);
int res = 0, cnt = 0;
for(int i = 0, p = 1; i < l; i++) {
if(nex[p][str[i] - 'a']) cnt++, p = nex[p][str[i] - 'a'];
else {
while(p && !nex[p][str[i] - 'a']) p = fa[p];
if(!p) cnt = 0, p = 1;
else cnt = len[p] + 1, p = nex[p][str[i] - 'a'];
}
dp[p] = max(dp[p], cnt);
}
for(int i = tot; i >= 2; i--)
dp[fa[i]] = max(dp[fa[i]], min(dp[i], len[fa[i]]));
for(int i = 2; i <= tot; i++) {
if(cntans[i] == -1 || dp[i] < cntans[i])
cntans[i] = dp[i];
dp[i] = 0;
}
// printf("%d\n", res);
return res;
}
}sam;
char s[N], t[N];
int k;
int main() {
memset(cntans, -1, sizeof(cntans));
int T, len;
ll ans;
scanf("%s", s + 1);
len = strlen(s + 1);
sam.init(len);
for(int i = 1; i <= len; i++)
sam.insert(s[i] - 'a');
while(~scanf("%s", t + 1)) {
sam.compare(t + 1);
}
int res = 0;
for(int i = 2; i <= sam.tot; i++)
res = max(res, cntans[i]);
printf("%d\n", res);
return 0;
}