后缀数组模板题,很久之前写过。
表示排名为
的后缀的位置
表示后缀
的排名
表示
与
的最长公共前缀,即排名相邻的两个后缀的LCP
#include <cstdio>
const int N = 102005, INF = 0x3f3f3f3f;
int n, m, t;
int a[1005][1005], sa[N], c[N], x[N], y[N], s[N];
int rank[N], height[N], vis[N], sta[N], top, id[N];
int read() {
int x = 0, f = 1;
char c = getchar();
while (c < '0' || c > '9') {
if (c == '-') f = -1;
c = getchar();
}
while (c >= '0' && c <= '9') {
x = (x << 3) + (x << 1) + (c ^ 48);
c = getchar();
}
return x * f;
}
int min(int x, int y) {
if (x <= y) return x; return y;
}
int max(int x, int y) {
if (x >= y) return x; return y;
}
void swap(int &x, int &y) {
x ^= y, y ^= x, x ^= y;
}
void get_sa() {
for (int i = 0; i < n; ++i) ++c[x[i] = s[i]];
for (int i = 1; i < m; ++i) c[i] += c[i-1];
for (int i = n - 1; i >= 0; --i) sa[--c[x[i]]] = i;
for (int k = 1; k <= n; k <<= 1) {
int p = 0;
for (int i = n - k; i < n; ++i) y[p++] = i;
for (int i = 0; i < n; ++i) if (sa[i] >= k) y[p++] = sa[i] - k;
for (int i = 0; i < m; ++i) c[i] = 0;
for (int i = 0; i < n; ++i) ++c[x[y[i]]];
for (int i = 1; i < m; ++i) c[i] += c[i-1];
for (int i = n - 1; i >= 0; --i) sa[--c[x[y[i]]]] = y[i];
for (int i = 0; i < n; ++i) swap(x[i], y[i]);
p = 1, x[sa[0]] = 0;
for (int i = 1; i < n; ++i)
x[sa[i]] = y[sa[i]] == y[sa[i-1]] && (sa[i]+k<n ? y[sa[i]+k] : -1) == (sa[i-1]+k<n ? y[sa[i-1]+k] : -1) ? p-1 : p++;
if (p >= n) break; m = p;
}
}
void get_height() {
int k = 0;
for (int i = 0; i < n; ++i) {
if (!x[i]) continue;
if (k) --k;
int j = sa[x[i]-1];
while (j+k<n && i+k<n && s[j+k]==s[i+k]) ++k;
height[x[i]] = k;
}
}
bool check(int x) {
while (top) vis[sta[top--]] = 0;
for (int i = 0; i < n; ++i) {
if (height[i] < x) while(top) vis[sta[top--]] = 0;
if (!vis[id[sa[i]]]) {
vis[id[sa[i]]] = 1;
sta[++top] = id[sa[i]];
if (top == t) return true;
}
}
return false;
}
int main() {
t = read(); int l = 0, r = INF, minn = INF, maxn = 0;
for (int i = 1; i <= t; ++i) {
a[i][0] = read(), a[i][1] = read();
r = min(r, a[i][0] - 1);
for (int j = 2; j <= a[i][0]; ++j) {
a[i][j] = read();
minn = min(minn, a[i][j] - a[i][j-1]);
maxn = max(maxn, a[i][j] - a[i][j-1]);
}
}
for (int i = 1; i <= t; ++i) {
for (int j = 2; j <= a[i][0]; ++j)
id[n] = i, s[n++] = a[i][j] - a[i][j-1] - minn;
s[n++] = ++maxn-minn;
}
for (int i = 0; i < n; ++i) m = max(m, s[i] + 1);
get_sa(), get_height();
while (l < r) {
int mid = l + ((r - l + 1) >> 1);
if (check(mid)) l = mid; else r = mid - 1;
}
printf("%d\n", l + 1);
return 0;
}