【BZOJ4698】[SDOI2008]Sandy的卡片

【BZOJ4698】[SDOI2008]Sandy的卡片

题面

flag倒了。

bzoj

洛谷

题解

首先题目的区间加很丑对吧,

将每个串差分一下,就可以转化为

求:

给定\(N\)个串,求他们的最长公共子串。

怎么办呢,按照后缀数组常用套路

我们用不同的未曾用过的字符将这些串连接起来

我们将\(lcp\)大于\(mid\)的串分组

如果一组内串的个数大于等于\(N\)个,就证明可以\(return\;1\)

否则若没有一组大于等于\(N\)返回\(0\)

代码

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring> 
#include <cmath> 
#include <algorithm>
using namespace std; 
inline int gi() {
    register int data = 0, w = 1;
    register char ch = 0;
    while (!isdigit(ch) && ch != '-') ch = getchar(); 
    if (ch == '-') w = -1, ch = getchar();
    while (isdigit(ch)) data = 10 * data + ch - '0', ch = getchar();
    return w * data; 
}
const int MAX_N = 2e6 + 5; 
int N, T, a[MAX_N], b[MAX_N], vis[MAX_N]; 
int sa[MAX_N], rnk[MAX_N], lcp[MAX_N]; 
void GetSA() {
#define cmp(i, j, k) (y[i] == y[j] && y[i + k] == y[j + k]) 
    static int x[MAX_N], y[MAX_N], bln[MAX_N];
    int M = 1e6; 
    for (int i = 1; i <= N; i++) bln[x[i] = a[i]]++; 
    for (int i = 1; i <= M; i++) bln[i] += bln[i - 1]; 
    for (int i = N; i >= 1; i--) sa[bln[x[i]]--] = i; 
    for (int k = 1; k <= N; k <<= 1) { 
        int p = 0; 
        for (int i = 0; i <= M; i++) y[i] = 0; 
        for (int i = N - k + 1; i <= N; i++) y[++p] = i; 
        for (int i = 1; i <= N; i++) if (sa[i] > k) y[++p] = sa[i] - k; 
        for (int i = 0; i <= M; i++) bln[i] = 0; 
        for (int i = 1; i <= N; i++) bln[x[y[i]]]++; 
        for (int i = 1; i <= M; i++) bln[i] += bln[i - 1]; 
        for (int i = N; i >= 1; i--) sa[bln[x[y[i]]]--] = y[i]; 
        swap(x, y); x[sa[1]] = p = 1; 
        for (int i = 2; i <= N; i++) x[sa[i]] = cmp(sa[i], sa[i - 1], k) ? p : ++p; 
        if (p >= N) break;
        M = p; 
    } 
}
void GetLcp() { 
    for (int i = 1; i <= N; i++) rnk[sa[i]] = i; 
    for (int i = 1, j = 0; i <= N; i++) {
        if (j) --j; 
        while (a[i + j] == a[sa[rnk[i] - 1] + j]) ++j; 
        lcp[rnk[i]] = j; 
    } 
} 
int col[MAX_N], tot; 
bool check(int v) {
    ++tot; int cnt = 0; 
    for (int i = 1; i <= N; i++) { 
        if (lcp[i] < v) ++tot, cnt = 0; 
        if (col[vis[sa[i]]] != tot) col[vis[sa[i]]] = tot, ++cnt; 
        if (cnt == T) return 1; 
    } 
    return 0; 
} 
const int dlt = 5e4; 
int main () { 
    T = gi(); 
    for (int i = 1; i <= T; i++) { 
        int m = gi(); 
        for (int j = 1; j <= m; j++) b[j] = gi(); 
        for (int j = 1; j <= m; j++) b[j] = b[j + 1] - b[j] + dlt; 
        for (int j = 1; j < m; j++) a[++N] = b[j], vis[N] = i; 
        a[++N] = i + 5e5; 
    }
    GetSA(); GetLcp(); 
    int l = 0, r = N, ans = 0; 
    while (l <= r) { 
        int mid = (l + r) >> 1; 
        if (check(mid)) l = mid + 1, ans = mid;
        else r = mid - 1; 
    } 
    printf("%d\n", ans + 1); 
    return 0; 
} 
posted @ 2019-01-22 19:21  heyujun  阅读(331)  评论(2编辑  收藏  举报