后缀数组板子

poj1743
下标从0开始版本

#include<iostream>
#include<stdio.h>
#include<string.h>
#include<string>
#define M 20005
using namespace std;
int x[M],y[M],sa[M],rk[M],c[M],h[M],s[M];
int n,i,l,r,mid,m,mx;

void build_sa(){                //m,p要比实际大1
    for(int i=0;i<m;i++)c[i]=0;
    for(int i=0;i<n;i++)c[x[i]=s[i]]++;
    for(int i=1;i<m;i++)c[i]+=c[i-1];
    for(int i=n-1;i>=0;i--)sa[--c[x[i]]]=i;
    for(int k=1;k<=n;k<<=1){
        int p=0;
        for(int i=n-k;i<n;i++)y[p++]=i;
        for(int i=0;i<n;i++)if(sa[i]>=k)y[p++]=sa[i]-k;
        
        for(int i=0;i<m;i++)c[i]=0;
        for(int i=0;i<n;i++)c[x[y[i]]]++;//实际上直接x就行
        for(int i=1;i<m;i++)c[i]+=c[i-1];
        for(int i=n-1;i>=0;i--)sa[--c[x[y[i]]]]=y[i];

        swap(x,y);
        p=1;x[sa[0]]=0;
        for(int i=1;i<n;i++)
            x[sa[i]]=
                y[sa[i-1]]==y[sa[i]]&&y[sa[i-1]+k]==y[sa[i]+k]?p-1:p++;
        if(p>=n)break;
        m=p;
    }
}

void get_heigh(){
    int k=0;
    for(int i=1;i<=n;i++)rk[sa[i]]=i;//最后加一位,第n位一定rk=0
    for(int i=0;i<n;i++){            //不遍历到n,rk就一定不为0
        if(k)k--;
        int j=sa[rk[i]-1];
        while(s[i+k]==s[j+k])k++;
        h[rk[i]]=k;
    }
}
int ck(int mid){
    int mi=sa[0],ma=sa[0];
    for(int i=1;i<n;i++){
        if(h[i]>=mid){
            mi=min(sa[i],mi);
            ma=max(sa[i],ma);
        }else{
            mi=sa[i];ma=sa[i];
        }
        if(ma-mi>mid)return 1;
    }
    return 0;
}
int main(){
    while(~scanf("%d",&n)&&n){
        mx=0;
        for(i=0;i<n;i++){
            scanf("%d",&s[i]);
            if(i){s[i-1]=s[i]-s[i-1]+88;mx=max(s[i-1],mx);}
        }
        s[n-1]=0;
        m=mx+1;
        build_sa();
        n--;
        get_heigh();
        l=0;r=n++;
        while(l<r){
            mid=(l+r)/2;
            if(ck(mid))l=mid+1;
            else r=mid;
        }
        if(!ck(l))l--;
        if(l+1<5)printf("0\n");
        else printf("%d\n",l+1);
    }
}
上一篇:hdu 3068 最长回文(manacher)


下一篇:vue服务端渲染的基本实现