首页 > 代码库 > 后缀数组

后缀数组

具体请看论文....

POJ 1743 Musical Theme

不重叠的最长重复子串

#include <cstdio>#include <cstring>#include <algorithm>#include <iostream>using namespace std;#define N 20100int p[N];int sa[N],rank[N],height[N];int wa[N],wb[N],c[N];//sa[i] 表示排名为i的下标//rank[i]表示i的排名//height[i]表示sa[i]和sa[i-1]的最长前缀void build_sa(int s[],int n,int m){    int i,j,p,*x = wa,*y = wb;    //初始化基数排序    for(i = 0;i < m;i ++)    c[i] = 0;    for(i = 0;i < n;i ++)    c[x[i] = s[i]] ++;    for(i = 1;i < m;i ++)    c[i] += c[i-1];    for(i = n-1;i >= 0;i --)    sa[--c[x[i]]] = i;    for(j = 1;j <= n;j <<= 1)    {        p = 0;        //y[i] 表示第二关键字排名为i的下标        for(i = n-j;i < n;i ++)        y[p++] = i;        //如果后缀长度不到j的,第二关键字排名靠前        for(i = 0;i < n;i ++)        if(sa[i] >= j) y[p++] = sa[i] - j;        //sa[i] < j的时候不可能为第二关键字,位置sa[i]-j的第二关键字为sa[i],        //他的排名为p        //按第一关键字排序        for(i = 0;i < m;i ++)        c[i] = 0;        for(i = 0;i < n;i ++)        c[x[y[i]]] ++;        for(i = 1;i < m;i ++)        c[i] += c[i-1];        //按y数组的存的下标顺序,基数排序        for(i = n-1;i >= 0;i --)        sa[--c[x[y[i]]]] = y[i];        swap(x,y);        //生成新的x数组,交换成y,是为了节省空间....        p = 1;x[sa[0]] = 0;        //如果两个关键字都一样,下次的第一关键字一样。        for(i = 1;i < n;i ++)        x[sa[i]] = y[sa[i-1]] == y[sa[i]]&&y[sa[i-1]+j] == y[sa[i]+j]?p-1:p++;        if(p >= n) break;        m = p;    }}void get_height(int s[],int n){    int i,j,k = 0;    for(i = 1;i <= n;i ++)    rank[sa[i]] = i;    //看论文,有证明    for(i = 0;i < n;i ++)    {        if(k) k--;        j = sa[rank[i]-1];        while(s[i+k]==s[j+k]) k ++;        height[rank[i]] = k;    }}int judge(int mid,int n){    int minz,maxz,i;    minz = maxz = sa[1];    for(i = 2;i <= n;i ++)    {        if(height[i] < mid)        {            minz = maxz = sa[i];        }        else        {            maxz = max(maxz,sa[i]);            minz = min(minz,sa[i]);            if(maxz-minz > mid)            return 1;        }    }    return 0;}int main(){    int n,i;    while(scanf("%d",&n)!=EOF)    {        if(n == 0) break;        for(i = 0;i < n;i ++)        scanf("%d",&p[i]);        for(i = 0;i < n-1;i ++)        p[i] = p[i+1] -  p[i] + 90;        n --;        p[n] = 0;        build_sa(p,n+1,200);        get_height(p,n);        int str,mid,end;        str = 1;        end = n/2;        while(str < end)        {            mid = (str+end + 1)/2;            if(judge(mid,n))            str = mid;            else            end = mid-1;        }        if(end >= 4)        printf("%d\n",end+1);        else        printf("0\n");    }    return 0;}
View Code