[POI2000] public string

Given string of no more than 5, find the longest common substring

The total length of not more than 1w

 

Several serially connected together to the intermediate separated by different characters

After obtaining height, half answer is k, find the number of each period of continuous and k is not less than the height of the array, which is determined by the prefix, and each contains a sub-string from the string

$ O (nlogn) $

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int maxn = 10000 + 10;
int n, m;
char s[maxn]; 
int sa[maxn], rank[maxn], height[maxn];
int tax[maxn], tp[maxn];
inline void tsort(){
    for(int i = 1; i <= m; i++) tax[i] = 0;
    for(int i = 1; i <= n; i++) tax[rank[i]]++;
    for(int i = 2; i <= m; i++) tax[i] += tax[i - 1];
    for(int i = n; i; i--) sa[tax[rank[tp[i]]]--] = tp[i];
}
inline bool cmp(int *arr, int l, int r, int k){
    return arr[l] == arr[r] && arr[l + k] == arr[r + k];
}
void suffix_sort(){
    m = 128;
    for(int i = 1; i <= n; i++) tp[i] = i;
    for(int i = 1; i <= n; i++) rank[i] = s[i];
    tsort();
    for(int k = 1, p = 0; p < n; k <<= 1, m = p){
        p = k;
        for(int i = 1; i <= k; i++) tp[i] = n - k + i;
        for(int i = 1; i <= n; i++) if(sa[i] > k) tp[++p] = sa[i] - k;
        tsort();
        swap(rank, tp);
        p = rank[sa[1]] = 1;
        for(int i = 2; i <= n; i++)
            rank[sa[i]] = cmp(tp, sa[i - 1], sa[i], k) ? p : ++p;
    }
    for(int i = 1, j, k = 0; i <= n; height[rank[i++]] = k)
        for(k ? k-- : 0, j = sa[rank[i] - 1]; s[j + k] == s[i + k]; k++);
}
int L[10], R[10], sum[10][maxn] = {0};
char temp[] = {'!', '@', '#', '$', 0};
int q[maxn], qcnt;
int main(){
    int N;
    scanf("%d", &N);
    n = 0;
    for(int i = 0; i < N; i++){
        L[i] = n + 1;
        scanf("%s", s + 1 + n);
        n += strlen(s + 1 + n);
        R[i] = n;
        s[++n] = temp[i];
    }
    s[n--] = 0;
    suffix_sort();
    for(int i = 0; i < N; i++){
        for(int j = L[i]; j <= R[i]; j++)
            sum[i][rank[j]]++;
        for(int j = 1; j <= n; j++)
            sum[i][j] += sum[i][j - 1];
    }
    int l = 1, r = maxn, mid, ans = 0;
    for(int i = 0; i < N; i++) r = min(r, R[i] - L[i] + 1);
    bool flag;
    while(l <= r){
        mid = l + r >> 1;
        qcnt = 0;
        for(int i = 1; i <= n; i++){
            if(height[i] < mid) q[++qcnt] = i;
        }
        for(int i = 2; i <= qcnt; i++){
            flag = true;
            for(int j = 0; j < N; j++) flag &= sum[j][q[i] - 1] - sum[j][q[i - 1] - 1] > 0;
            if(flag) break;
        }
        if(flag){
            ans = mid;
            l = mid + 1;
        }
        else r = mid - 1;
    }
    printf("%d\n", ans);
    return 0;
}

 

Guess you like

Origin www.cnblogs.com/ruoruoruo/p/11594284.html