zoukankan      html  css  js  c++  java
  • [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
    ", ans);
        return 0;
    }
  • 相关阅读:
    MySql之基础
    web篇---jQuery
    前端篇---CSS
    前端篇--HTML
    Python篇1.17---多进程
    Python篇1.16---socket编程
    Python篇1.15---模块与包
    Python番外篇---函数
    python番外篇---变量与数据类型
    【认真的完整版翻唱!】红莲之箭【あるふぁきゅん。】
  • 原文地址:https://www.cnblogs.com/ruoruoruo/p/11594284.html
Copyright © 2011-2022 走看看