Description:
给 \(n\) 个长度 \(\le 10^5\) 的字符串,求它们最长公共子串。\(n\le 10\)
Solution:
把第一个字符串的 \(SAM\) 建出来,然后其他串在上跑,跑到一个点记录当前匹配的最长子串,但最后答案是和每个点匹配的最长中最小的去取 \(min\),所以在自动机上跑的时候维护一个 \(lcs[x]\) 和 \(slcs[x]\) 分别表示当前正在跑的串在这个节点匹配到的最长子串长度和之前所有的最小值,由于一个点匹配上了,它所有祖先都会匹配到,所以每跑完后每个点的 \(lcs[x]\) 要和它的儿子取 \(max\) 同时和自己的 \(maxlen\) 取 \(min\) ,此时 \(slcs\) 再和 \(lcs[x]\) 取 \(min\) ,别忘记处理完一个串后要清空 \(lcs[x]\)。
Code:
#include
#include
#include
#include
#include
typedef long long LL;
typedef unsigned long long uLL;
#define inline __inline__ __attribute__ ((always_inline))
#define SZ(x) ((int)x.size())
#define ALL(x) (x).begin(), (x).end()
#define MP(x, y) std::make_pair(x, y)
#define DEBUG(...) fprintf(stderr, __VA_ARGS__)
#define GO cerr << "GO" << endl;
using namespace std;
inline void proc_status()
{
ifstream t("/proc/self/status");
cerr << string(istreambuf_iterator(t), istreambuf_iterator()) << endl;
}
template inline T read()
{
register int x = 0; register int f = 1; register char c;
while (!isdigit(c = getchar())) if (c == '-') f = -1;
while (x = (x << 1) + (x << 3) + (c xor 48), isdigit(c = getchar()));
return x * f;
}
template inline bool chkmin(T &a, T b) { return a > b ? a = b, 1 : 0; }
template inline bool chkmax(T &a, T b) { return a < b ? a = b, 1 : 0; }
const int maxN = (int) 1e5;
int len[12], n;
int rk[maxN * 2], lcs[maxN * 2], slcs[maxN * 2];
char str[12][maxN + 2];
namespace SAM
{
int Ncnt, last;
struct Status
{ int len, link, ch[26]; } st[maxN * 2];
inline void init()
{ st[0].len = 0, st[0].link = -1, Ncnt = 0; }
inline void insert(char ch)
{
int c = ch - 'a';
int cur = ++Ncnt;
int p = last;
st[cur].len = st[last].len + 1;
while (p != -1 and !st[p].ch[c])
{
st[p].ch[c] = cur;
p = st[p].link;
}
if (p == -1)
st[cur].link = 0;
else
{
int q = st[p].ch[c];
if (st[q].len == st[p].len + 1)
st[cur].link = q;
else
{
int clone = ++Ncnt;
st[clone] = st[q];
st[clone].len = st[p].len + 1;
while (p != -1 and st[p].ch[c] == q)
{
st[p].ch[c] = clone;
p = st[p].link;
}
st[q].link = st[cur].link = clone;
}
}
last = cur;
}
}
using namespace SAM;
inline void Input()
{
while (scanf("%s", str[++n] + 1) != EOF)
len[n] = strlen(str[n] + 1);
n--;
}
inline void Init()
{
init();
for (register int i = 1; i <= len[1]; ++i)
insert(str[1][i]);
static int buc[maxN * 2];
for (register int i = 1; i <= Ncnt; ++i) buc[st[i].len]++;
for (register int i = 1; i <= Ncnt; ++i) buc[i] += buc[i - 1];
for (register int i = 1; i <= Ncnt; ++i) rk[buc[st[i].len]--] = i;
for (register int i = 0; i <= Ncnt; ++i) slcs[i] = (int) 1e5 + 1;
}
inline void Solve()
{
for (int t = 2; t <= n; ++t)
{
for (register int i = 0; i <= Ncnt; ++i)
lcs[i] = 0;
int cur = 0, L = 0;
for (register int i = 1; i <= len[t]; ++i)
{
int c = str[t][i] - 'a';
while (cur != -1 and !st[cur].ch[c])
{
cur = st[cur].link;
if (cur != -1)
L = st[cur].len;
}
if (cur == -1)
cur = 0;
else
{
L++;
cur = st[cur].ch[c];
chkmax(lcs[cur], L);
}
}
for (register int i = Ncnt; i >= 1; --i)
{
int cur = rk[i];
chkmin(lcs[cur], st[cur].len);
chkmin(slcs[cur], lcs[cur]);
if (cur) chkmax(lcs[st[cur].link], lcs[cur]);
}
}
int ans = 0;
for (register int i = 1; i <= Ncnt; ++i)
chkmax(ans, slcs[i]);
cout << ans << '\n';
}
int main()
{
#ifndef ONLINE_JUDGE
freopen("xhc.in", "r", stdin);
freopen("xhc.out", "w", stdout);
#endif
Input();
Init();
Solve();
return 0;
}