POJ 1724 Corporate Identity 后缀数组

来源:互联网 发布:阴茎上白色米粒知乎 编辑:程序博客网 时间:2024/06/05 14:11

题意:给出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[1000010];char str[10010];int n,N,pos,len;bool vis[4010];bool judge(int mid){    int cnt = 0;    for(int i = 0; i < n; ++i){        if(height[i] < mid){            memset(vis,0,sizeof(vis));            cnt = 0;            continue;        }        int l1 = sa[i] / (len+1), l2 = sa[i-1] / (len+1);        if(!vis[l1])            vis[l1] = true, cnt++;        if(!vis[l2])            vis[l2] = true, cnt++;        if(cnt == N){            pos = sa[i];            return true;        }    }    return false;}int main(void){    ///freopen("input.txt","r",stdin);    //freopen("out.txt","w",stdout);    while(scanf("%d",&N),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 == 0)            puts("IDENTITY LOST");        else{            for(int i = 0; i < lb; ++i)                putchar(r[pos+i]);            putchar('\n');        }    }    return 0;}

0 0