POJ 1743 Musical Theme(后缀数组求不可重叠最长重复子串)

2014-11-24 10:35:03 · 作者: · 浏览: 0

题目:给出一些音符,求出最长的重复出现的旋转长度。


从题目中的意思可以知道,只要满足相邻的差相等便可以了,那我们建立一个相邻并非的数组,题目要求的便是求最长的重复子串长度,而且不可重叠。

由于 相邻差可能为负,则统一加上100,转变为0-200之间的数即可。

之后求出height数组,表示的是相邻后缀的最长公共前缀。

二分答案,然后进行判定

按height就可以对后缀进行分组,height如果大于长度,则我们需要判断是否重叠,通过sa的差值即可。详见代码


[cpp]
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#define maxn 50005
#define eps 1e-8
#define zero(a) fabs(a) using namespace std;
//以下为倍增算法求后缀数组
int wa[maxn],wb[maxn],wv[maxn],Ws[maxn];
int cmp(int *r,int a,int b,int l)
{return r[a]==r[b]&&r[a+l]==r[b+l];}
void da(const int *r,int *sa,int n,int m){
int i,j,p,*x=wa,*y=wb,*t;
for(i=0;i for(i=0;i for(i=1;i for(i=n-1;i>=0;i--) sa[--Ws[x[i]]]=i;
for(j=1,p=1;p for(p=0,i=n-j;i for(i=0;i=j) y[p++]=sa[i]-j;
for(i=0;i for(i=0;i for(i=0;i for(i=1;i 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 x[sa[i]]=cmp(y,sa[i-1],sa[i],j) p-1:p++;
}
return;
}
int sa[maxn],Rank[maxn],height[maxn];
//求height数组
void calheight(const int *r,int *sa,int n){
int i,j,k=0;
for(i=1;i<=n;i++) Rank[sa[i]]=i;
for(i=0;i for(k k--:0,j=sa[Rank[i]-1];r[i+k]==r[j+k];k++);
return;
}
int n;
int a[maxn],b[maxn];
bool check(int m){
int mmax=0,mmin=n;
for(int i=1;i<=n;i++){
if(height[i] mmax=sa[i];
mmin=sa[i];
}
else{
mmax=max(mmax,max(sa[i],sa[i-1]));
mmin=min(mmin,min(sa[i],sa[i-1]));
if(mmax-mmin>m) return true;
}
}
return false;
}
int main(){
while(scanf("%d",&n)!=EOF&&n){
for(int i=0;i for(int i=0;i n--;
b[n]=0;
da(b,sa,n+1,200);
calheight(b,sa,n);
if(!check(4)){
printf("0\n");
continue;
}
int ans,low=0,high=n,mid;
while(low<=high){
mid=(low+high)/2;
if(check(mid)){
ans=mid;
low=mid+1;
}
else
high=mid-1;
}
printf("%d\n",ans+1);
}
return 0;