poj1226

题解:

后缀数组

把所有串先翻转,用一个没有出现过的字符连接

然后再把所有串接起来

然后用一个没有出现过的字符连接

然后二分

在后缀数组上判断lcp

代码:

#include<cstdio>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<set>
using namespace std;
typedef long long LL;
const int N=100*100*5;
char str[105];
int r[N],len,n,t,Index[N],Rank[N],height[N],sa[N],wa[N],wb[N],wv[N],WS[N];
int cmp(int *r,int a,int b,int l)
{
    return r[a]==r[b]&&r[a+l]==r[b+l];
}
void da(int *r,int *sa,int n,int m)
{
    int p,*x=wa,*y=wb,*t;
    for (int i=0;i<m;i++)WS[i]=0;
    for (int i=0;i<n;i++)WS[x[i]=r[i]]++;
    for (int i=1;i<m;i++)WS[i]+=WS[i-1];
    for (int i=n-1;i>=0;i--)sa[--WS[x[i]]]=i;
    for (int j=1,p=1;p<n;j*=2,m=p)
     {
         p=0;
        for (int i=n-j;i<n;i++)y[p++]=i;
        for (int i=0;i<n;i++)
         if (sa[i]>=j)y[p++]=sa[i]-j;
        for (int i=0;i<n;i++)wv[i]=x[y[i]];
        for (int i=0;i<m;i++)WS[i]=0;
        for (int i=0;i<n;i++)WS[wv[i]]++;
        for (int i=1;i<m;i++)WS[i]+=WS[i-1];
        for (int i=n-1;i>=0;i--)sa[--WS[wv[i]]]=y[i];
        t=x,x=y,y=t,p=1,x[sa[0]]=0;     
        for (int i=1;i<n;i++)
         x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
     } 
    return;
}
void calheight(int *r,int *sa,int n)
{
    int k=0;
    for (int i=1;i<=n;i++)Rank[sa[i]]=i;
    for (int i=0;i<n;height[Rank[i++]]=k)
     {
         k?k--:0;
         for (int j=sa[Rank[i]-1];r[i+k]==r[j+k];k++);
     }
    return;
}
int check(int x)
{
    set<int>se;
    for (int i=1;i<len;i++)
     {
        if (height[i]>=x)
         { 
            se.insert(Index[sa[i]]);
            se.insert(Index[sa[i-1]]);
         }
        else
         {
            if (se.size()==n)return 1;
            se.clear();
         }
     }
    if (se.size()==n)return 1;
    return false;
}
void solve()
{
    int L=1,R=100,ans=0;
    while (R>=L)
     {
        int mid=(L+R)/2;
        if (check(mid))
         {
            ans=mid;
            L=mid+1;
         }
        else R=mid-1;
     }
    printf("%d
",ans);
}
int main()
{
    scanf("%d", &t);
    while (t--)
     {
        scanf("%d",&n);len=0;
        for (int i=1,val=0;i<=n;i++)
         {
            scanf("%s",&str);
            for (int j=0;j<strlen(str);j++)
             { 
                Index[len]=i; 
                r[len++]=(str[j]-'A'+2*n+1);
             }
            Index[len]=i; 
            r[len++]=val++; 
            for (int j=strlen(str)-1;j>=0;j--)
             {
                Index[len]=i;
                r[len++]=(str[j]-'A'+2*n+1);
             }
            Index[len]=i;
            r[len++]=val++; 
         }
        da(r,sa,len,300);
        calheight(r,sa,len-1);
        solve();
     }
    return 0;
}
原文地址:https://www.cnblogs.com/xuanyiming/p/8490228.html