导航

POJ 1743 后缀数组不重叠最长重复子串

Posted on 2016-06-03 16:06  tun~  阅读(112)  评论(0编辑  收藏  举报
#include<stdio.h>
#include<string.h>
#include<algorithm>
#define maxn 30000
using namespace std;
int n;
int jilu[maxn];
int wa[maxn],wb[maxn],wv[maxn],ws[maxn],r[maxn],sa[maxn],rankk[maxn],height[maxn];//r数组是将原始字符串进行整数化
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){//待排序字符串长度是n,从0开始,最大是m-1
    int i,j,p,*x=wa,*y=wb,*t;
    for(i=0;i<m;i++)ws[i]=0;
    for(i=0;i<n;i++)ws[x[i]=r[i]]++;
    for(i=1;i<m;i++)ws[i]+=ws[i-1];
    for(i=n-1;i>=0;i--)sa[--ws[x[i]]]=i;
    for(j=1,p=1;p<n;j*=2,m=p){
        for(p=0,i=n-j;i<n;i++)y[p++]=i;
        for(i=0;i<n;i++)if(sa[i]>=j)y[p++]=sa[i]-j;
        for(i=0;i<n;i++)wv[i]=x[y[i]];
        for(i=0;i<m;i++)ws[i]=0;
        for(i=0;i<n;i++)ws[wv[i]]++;
        for(i=1;i<m;i++)ws[i]+=ws[i-1];
        for(i=n-1;i>=0;i--)sa[--ws[wv[i]]]=y[i];
        for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++)
            x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++;
    }
}
void calheight(int *r,int *sa,int n){
    int i,j,k=0;
    for(i=1;i<=n;i++) rankk[sa[i]]=i;
    for(i=0;i<n;height[rankk[i++]]=k)
    for(k?k--:0,j=sa[rankk[i]-1];r[i+k]==r[j+k];k++);
    return;
}
bool ok(int mid){
    int mmax=-1,mmin=99999999;
    for(int i=1;i<n;i++){
        if(height[i]<mid){
            if(mmax-mmin>=mid)return 1;
            mmax=sa[i];
            mmin=sa[i];
        }
        mmax=max(sa[i],mmax);
        mmin=min(sa[i],mmin);
    }
    if(mmax-mmin>=mid)return 1;
    else return 0;
}
int main()
{
    while(scanf("%d",&n)!=EOF){
        if(n==0)break;
        for(int i=0;i<n;i++){
            scanf("%d",&jilu[i]);
            if(i>0)r[i-1]=jilu[i]-jilu[i-1]+100;
        }
        r[n-1]=0;
        da(r,sa,n,200);
        calheight(r,sa,n-1);
        int l=0,r=n;
        while(l<=r){
            int mid=(l+r)>>1;
            if(ok(mid))l=mid+1;
            else r=mid-1;
        }
        r++;
        if(r<5)r=0;
        printf("%d\n",r);
    }
}