POJ 3080 Blue Jeans 后缀数组

题意:给出N个字符串,求出最长的子串,在每个字符串中都出现。

思路:二分答案,对height进行数组,判断即可。

代码如下:

#include <cstring>
#include <cstdio>
#include <algorithm>
#include <set>

using namespace std;

    static const int maxn =1000100;
    int rk[maxn],sa[maxn],height[maxn];
    int a[maxn],b[maxn],cont[200000];
    //待排序字符串为r,长度为n,范围r[0] - r[n-1],值额范围0 - n-1.
    //字符集为m,范围1 - m;

    void radix_sort(int * r, int *a, int *b, int n, int m){//将a按照r进行基数排序,储存到b,长度为n,字符集为m
        memset(cont,0,sizeof(cont));
        for(int i = 0; i < n; ++i) ++cont[r[a[i]]];
        for(int i = 1; i <= m; ++i) cont[i] += cont[i-1];
        for(int i = n -1; i >= 0; --i) b[--cont[r[a[i]]]] = a[i];
    }

    void calc_sa(int*r, int n, int m){
        for(int i = 0; i < n; ++i) rk[i] =i;
        radix_sort(r,rk,sa,n,m);

        rk[sa[0]] = 0;
        for(int i = 1; i < n; ++i)
            rk[sa[i]]= rk[sa[i-1]] +(r[sa[i]]!=r[sa[i-1]]);
        for(int i = 0; 1<<i< n; ++i){
            for(int j = 0; j < n; ++j){
                a[j] = rk[j]+1;
                b[j] = j + (1<<i) >=n? 0: rk[j + (1<<i)] + 1;
                sa[j] = j;
            }
            radix_sort(b,sa,rk,n,n);
            radix_sort(a,rk,sa,n,n);
            rk[sa[0]] = 0;
            for(int j = 1; j < n; ++j){
                rk[sa[j]] = rk[sa[j-1]] + (a[sa[j-1]] != a[sa[j]] || b[sa[j-1]] != b[sa[j]]);
            }
        }
    }

    void calc_height(int * r,int n) {//计算height
        for(int i = 0 ; i < n; ++i) rk[sa[i]] = i;
        int h = 0;
        for(int i = 0; i < n; ++i){
            h = h == 0?0: h - 1;
            if(rk[i]!= 0)
                while(r[i + h] == r[sa[rk[i]-1] + h]) h++;
            height[rk[i]] = h;
        }
    }

int r[1010];
char str[1010];
int p[1010];
int n,N,pos,len,T;
set<int> record;

bool judge(int mid)
{
    for(int i = 0; i < n; ++i){
        if(height[i] < mid){
            record.clear();
            continue;
        }
        record.insert(sa[i]/(len+1));
        record.insert(sa[i-1]/(len+1));
        if(record.size() == N){
            pos = sa[i];
            return true;
        }
    }
    return false;
}

int main(void)
{
    //freopen("input.txt","r",stdin);
    //freopen("out.txt","w",stdout);
    scanf("%d",&T);
    while(T--){
        scanf("%d",&N);
        n = 0;
        for(int i = 0; i < N; ++i){
            scanf("%s",str);
            for(int j = 0; str[j];++j)
                r[n++] = str[j];
            r[n++] = 1000+i;
        }
        len = strlen(str);
        calc_sa(r,n,6000);
        calc_height(r,n);
        int lb = 0, ub = len + 1;
        while(lb + 1 < ub){
            int mid = (lb + ub) >> 1;
            if(judge(mid)) lb = mid;
            else ub = mid;
        }
        //printf("%d\n",lb);
        if(lb < 3)
            puts("no significant commonalities");
        else{
            for(int i = 0; i < lb; ++i)
                putchar(r[pos+i]);
            putchar('\n');
        }
    }
    return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值