[POI2000]公共串

Posted ruoruoruo

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[POI2000]公共串相关的知识,希望对你有一定的参考价值。

给出不超过5个字符串,求最长公共子串

总长度不超过1w

 

把几个串接到一起中间用不同的字符隔开

求出height之后,二分答案为k,在height数组中找到每一段连续的且均不小于k的数,用前缀和判断里面是否包含了来自每一个字符串的子串

$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;

 

以上是关于[POI2000]公共串的主要内容,如果未能解决你的问题,请参考以下文章

[BZOJ2946][Poi2000]公共串 后缀自动机

[bzoj2946][Poi2000]公共串_后缀数组_二分

[Poi2000]公共串

[POI2000]公共串 - 后缀数组

[POI2000]公共串

bzoj 2946 [Poi2000]公共串