2946: [Poi2000]公共串 后缀数组

来源:互联网 发布:程序员平均年龄 编辑:程序博客网 时间:2024/05/03 13:47

后缀数组,我们可以二分答案,然后对height分组,然后判断一下有没有分别出现在各个串中的后缀。

#include<iostream>#include<cstdio>#include<cstring>#include<algorithm>#define N 11000#define inf 1000000007using namespace std;int n,l,r,ans,len;int sa[N],cc[N],height[N],rank[N],t1[N],t2[N];int st[10];char s[N];bool q[10];inline bool cmp(int *y,int a,int b,int k){    int arank1=y[a];    int brank1=y[b];    int arank2=a+k>=len?-1:y[a+k];    int brank2=b+k>=len?-1:y[b+k];    return arank1==brank1&&arank2==brank2;}inline void make_sa(){    int *x=t1,*y=t2,m=256;    for (int i=0;i<m;i++) cc[i]=0;    for (int i=0;i<len;i++) ++cc[x[i]=s[i]];    for (int i=1;i<m;i++) cc[i]+=cc[i-1];    for (int i=len-1;~i;i--) sa[--cc[x[i]]]=i;    for (int k=1;k<len;k<<=1)    {        int p=0;        for (int i=len-k;i<len;i++) y[p++]=i;        for (int i=0;i<len;i++)            if (sa[i]>=k) y[p++]=sa[i]-k;        for (int i=0;i<m;i++) cc[i]=0;        for (int i=0;i<len;i++) ++cc[x[y[i]]];        for (int i=1;i<m;i++) cc[i]+=cc[i-1];        for (int i=len-1;~i;i--) sa[--cc[x[y[i]]]]=y[i];        swap(x,y); m=1; x[sa[0]]=0;        for (int i=1;i<len;i++)            x[sa[i]]=cmp(y,sa[i-1],sa[i],k)?m-1:m++;        if (m>=len) break;    }}inline void make_height(){    for (int i=0;i<len;i++) rank[sa[i]]=i;    int k=0;    height[0]=0;    for (int i=0;i<len;i++)    {        if (!rank[i]) continue;        int j=sa[rank[i]-1];        if (k) k--;        while (s[i+k]==s[j+k]) k++;        height[rank[i]]=k;    }}inline int find(int x){    if (s[x]=='&') return 0;    for (int i=2;i<=n;i++)        if (x<st[i]) return i-1;    return n;}inline bool judge(int mid){    int now=1;    while (now<len)    {        if (height[now]>=mid)        {            memset(q,false,sizeof(q));            q[find(sa[now-1])]=true;            while (height[now]>=mid&&now<len)            {                q[find(sa[now])]=true;                now++;            }            int flag=1;            for (int i=1;i<=n;i++)                if (!q[i])                 {                    flag=0;                    break;                }            if (flag) return true;        }        else now++;    }    return false;}int main(){    scanf("%d",&n); r=inf;    for (int i=1;i<=n;i++)    {        scanf("%s",s+len);        int tmp=strlen(s+len);        len+=tmp;        r=min(r,tmp);        s[len]='&';        st[i+1]=len;        len++;    }    make_sa();    make_height();    while (l<=r)    {        int mid=l+r>>1;        if (judge(mid)) ans=mid,l=mid+1;         else r=mid-1;    }    cout << ans << endl;    return 0;}
0 0
原创粉丝点击