bzoj2946
后缀数组+二分
中间加个字符,然后二分判断即可
#include<bits/stdc++.h> using namespace std; typedef long long ll; const int N = 100010; int n, top, k, tot, m, ans; int a[N], sa[N], rank[N], temp[N], lcp[N], belong[N]; bool flag[6]; char c[N], s[N]; bool cp(int i, int j) { if(rank[i] != rank[j]) return rank[i] < rank[j]; int ri = i + k <= n ? rank[i + k] : -1; int rj = j + k <= n ? rank[j + k] : -1; return ri < rj; } void Sa() { for(int i = 1; i <= n; ++i) { sa[i] = i; rank[i] = s[i]; } for(k = 1; k <= n; k <<= 1) { sort(sa + 1, sa + n + 1, cp); temp[sa[1]] = 1; for(int i = 2; i <= n; ++i) temp[sa[i]] = temp[sa[i - 1]] + (cp(sa[i - 1], sa[i])); for(int i = 1; i <= n; ++i) rank[i] = temp[i]; } } void Lcp() { for(int i = 1; i <= n; ++i) rank[sa[i]] = i; int h = 0; for(int i = 1; i <= n; ++i) { int j = sa[rank[i] - 1]; if(rank[i] <= 1) continue; if(h) --h; for(; i + h <= n && j + h <= n; ++h) if(s[i + h] != s[j + h]) break; lcp[rank[i] - 1] = h; } } bool C(int x) { for(int i = 1; i < n; ++i) { bool ff = true; if(lcp[i] >= x) { flag[belong[sa[i]]] = flag[belong[sa[i + 1]]] = true; for(int i = 1; i <= m; ++i) if(!flag[i]) { ff = false; break; } if(ff) return true; } else memset(flag, false, sizeof(flag)); } return false; } int main() { scanf("%d", &m); for(int i = 1; i <= m; ++i) { scanf("%s", c + 1); for(int j = 1; j <= strlen(c + 1); ++j) { s[++n] = c[j]; belong[n] = i; } s[++n] = '#' + i; } Sa(); Lcp(); int l = 0, r = 100000; while(r - l > 1) { int mid = (l + r) >> 1; if(C(mid)) l = ans = mid; else r = mid; } printf("%d\n", ans); return 0; }