【后缀数组】[POJ1743]Musical Theme 乐曲主旋律

题目:
后缀数组模板题,做法参见罗穗骞论文。
自认为代码写得比较好看。

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
#define MAXN 500000
#define MAXD 200
int array[4][MAXN*2+10],height[MAXN+10],ans;
int *nsa,*rk,*nrk,*sa;
int a[MAXN+10],n,b[MAXN+10];
void Read(int &x){
    char c;
    while(c=getchar(),c!=EOF)
        if(c>='0'&&c<='9'){
            x=c-'0';
            while(c=getchar(),c>='0'&&c<='9')
                x=x*10+c-'0';
            ungetc(c,stdin);
            return;
        }
}
void init(){
    Read(a[1]);
    for(int i=2;i<=n;i++){
        Read(a[i]);
        a[i-1]=a[i]-a[i-1]+100;
    }
    a[n]=-1;
    n--;
}
void cal_sa(){
    int i,k;
    sa=array[0],nsa=array[1],rk=array[2],nrk=array[3];
    memset(b,0,sizeof b);
    for(i=1;i<=n;i++)
        b[a[i]]++;
    for(i=1;i<=MAXD;i++)
        b[i]+=b[i-1];
    for(i=1;i<=n;i++)
        sa[b[a[i]]--]=i;
    for(i=1;i<=n;i++){
        rk[sa[i]]=rk[sa[i-1]];
        if(a[sa[i]]!=a[sa[i-1]])
            rk[sa[i]]++;
    }
    for(k=1;k<n&&rk[sa[n]] < n;k<<=1){
        for(i=1;i<=n;i++)
            b[rk[sa[i]]]=i;
        for(i=n;i;i--)
            if(sa[i]>k)
                nsa[b[rk[sa[i]-k]]--]=sa[i]-k;
        for(i=n-k+1;i<=n;i++)
            nsa[b[rk[i]]--]=i;
        for(i=1;i<=n;i++){
            nrk[nsa[i]]=nrk[nsa[i-1]];
            if(rk[nsa[i]]!=rk[nsa[i-1]]||rk[nsa[i]+k]!=rk[nsa[i-1]+k])
                nrk[nsa[i]]++;
        }
        swap(sa,nsa);
        swap(rk,nrk);
    }
}
void cal_height(){
    int i,k=0,j;
    for(i=1;i<=n;i++)
        if(rk[i]==1)
            height[rk[1]]=0;
        else{
            if(k>0)
                k--;
            for(j=sa[rk[i]-1];a[i+k]==a[j+k];k++);
            height[rk[i]]=k;
        }
}
bool check(int len){
    int mx=sa[1],mi=sa[1],i;
    for(i=2;i<=n;i++){
        if(height[i]>=len)
            mx=max(mx,sa[i]),mi=min(mi,sa[i]);
        else{
            if(mx-mi>len)    //两个串+1后可能有重叠
                return 1;
            mx=mi=sa[i];
        }
    }
    if(mx-mi>len)
        return 1;
    return 0;
}
void partition(int l,int r){
    int mid;
    while(l<=r){
        mid=(l+r)>>1;
        if(check(mid))
            l=mid+1,ans=mid;
        else
            r=mid-1;
    }
}
int main()
{
    while(Read(n),n){
        ans=-1;
        init();
        cal_sa();
        cal_height();
        partition(4,n);
        printf("%d\n",ans+1);
    }
}
posted @ 2015-12-14 13:47  outer_form  阅读(155)  评论(0编辑  收藏  举报