首页 > 代码库 > POJ-1743 Musical Theme(后缀数组)

POJ-1743 Musical Theme(后缀数组)

题目大意:给一个整数序列,找出最长的连续变化相同的、至少出现两次并且不相重叠一个子序列。

题目分析:二分枚举长度进行判定。

 

代码如下:

# include<iostream># include<cstdio># include<cstring># include<algorithm>using namespace std;# define mid (l+(r-l)/2)const int N=20000;int SA[N+5],height[N+5];int *rk,*tSA;int n,a[N+5],cnt[N+5];bool same(int i,int j,int k){    if(tSA[i]!=tSA[j]) return false;    if(i+k>=n&&j+k>=n) return true;    if(i+k>=n&&j+k<n) return false;    if(i+k<n&&j+k>=n) return false;    return tSA[i+k]==tSA[j+k];}void buildSA(){    int m=180;    for(int i=0;i<m;++i) cnt[i]=0;    for(int i=0;i<n;++i) ++cnt[rk[i]=a[i]];    for(int i=1;i<m;++i) cnt[i]+=cnt[i-1];    for(int i=n-1;i>=0;--i) SA[--cnt[rk[i]]]=i;	    for(int k=1;k<n;k<<=1){        int p=0;        for(int i=n-k;i<n;++i) tSA[p++]=i;        for(int i=0;i<n;++i) if(SA[i]>=k) tSA[p++]=SA[i]-k;        for(int i=0;i<m;++i) cnt[i]=0;        for(int i=0;i<n;++i) ++cnt[rk[tSA[i]]];        for(int i=1;i<m;++i) cnt[i]+=cnt[i-1];        for(int i=n-1;i>=0;--i) SA[--cnt[rk[tSA[i]]]]=tSA[i];        swap(rk,tSA);        p=1;        rk[SA[0]]=0;        for(int i=1;i<n;++i){            if(same(SA[i],SA[i-1],k)) rk[SA[i]]=p-1;            else rk[SA[i]]=p++;        }        if(p>=n) break;        m=p;    }}void getHeight(){    for(int i=0;i<n;++i) rk[SA[i]]=i;    int k=0;    height[0]=0;    for(int i=0;i<n;++i){		if(rk[i]==0) k=0;		else{			if(k) --k;			int j=SA[rk[i]-1];			while(i+k<n&&j+k<n&&a[i+k]==a[j+k]) ++k;			height[rk[i]]=k;		}    }}bool ok(int x){	int maxn=SA[0],minn=SA[0];	for(int i=1;i<n;++i){		if(minn+x<maxn) return true;		if(height[i]>=x){			maxn=max(maxn,SA[i]);			minn=min(minn,SA[i]);		}else{			maxn=minn=SA[i];		}	}	return minn+x<maxn;}void init(){    rk=new int[n+5];    tSA=new int[n+5];}void destroy(){    delete []rk;    delete []tSA;}int main(){    while(scanf("%d",&n)&&n)    {        init();        for(int i=0;i<n;++i){            scanf("%d",a+i);            --a[i];        }		--n;		int temp=a[0];		for(int i=0;i<n;++i){			a[i]=a[i+1]-temp+87;			temp=a[i+1];		}		        buildSA();        getHeight();				//二分枚举最短的不满足条件的		int l=4,r=n;		while(l<r){			if(ok(mid)) l=mid+1;			else r=mid;		}		printf("%d\n",l>=5?l:0);        destroy();    }    return 0;}

  

POJ-1743 Musical Theme(后缀数组)