后缀数组(不可重叠最长重复子串)
2016-12-14 21:29
369 查看
poj 1743
二分答案,把题目变成判定性问题:判断是否
存在两个长度为k的子串是相同的,且不重叠。解决这个问题的关键还是利用
height数组。把排序后的后缀分成若干组,其中每组的后缀之间的height值都
不小于k。
有希望成为最长公共前缀不小于k的两个后缀一定在同一组。然
后对于每组后缀,只须判断每个后缀的sa值的最大值和最小值之差是否不小于
k。如果有一组满足,则说明存在,否则不存在。
二分答案,把题目变成判定性问题:判断是否
存在两个长度为k的子串是相同的,且不重叠。解决这个问题的关键还是利用
height数组。把排序后的后缀分成若干组,其中每组的后缀之间的height值都
不小于k。
有希望成为最长公共前缀不小于k的两个后缀一定在同一组。然
后对于每组后缀,只须判断每个后缀的sa值的最大值和最小值之差是否不小于
k。如果有一组满足,则说明存在,否则不存在。
#include<cstdio>//sa为后缀数组,把后缀从小到大排序把后缀开头存起来,rank为名次数组,以i开头的后缀在所有后缀中排第几 #include<cstring> #include<cstdlib> #include<iostream> #include<algorithm> #define F(x) ((x)/3+((x)%3==1?0:tb)) #define G(x) ((x)<tb?(x)*3+1:((x)-tb)*3+2) using namespace std; const int maxn=1e6+10; int wa[maxn],wb[maxn],ww[maxn],wv[maxn],n; int cmp(int *r,int a,int b,int l) { return r[a]==r[b]&&r[a+l]==r[b+l]; } void da(int *r,int *sa,int n,int m) { int i,j,p,*x=wa,*y=wb,*t; for(i=0; i<m; i++) ww[i]=0; for(i=0; i<n; i++) ww[x[i]=r[i]]++; for(i=1; i<m; i++) ww[i]+=ww[i-1]; for(i=n-1; i>=0; i--) sa[--ww[x[i]]]=i; //处理长度为一的字符串,得到sa数组 for(j=1,p=1; p<n; j*=2,m=p) //倍增法求sa { for(p=0,i=n-j; i<n; i++) y[p++]=i; for(i=0; i<n; i++) if(sa[i]>=j) y[p++]=sa[i]-j;//利用上次的sa直接求出按第二个关键字排序 for(i=0; i<n; i++) wv[i]=x[y[i]]; //第二关键字的排序得出第一关键字的顺序 for(i=0; i<m; i++) ww[i]=0; for(i=0; i<n; i++) ww[wv[i]]++; for(i=1; i<m; i++) ww[i]+=ww[i-1]; for(i=n-1; i>=0; i--) sa[--ww[wv[i]]]=y[i]; //根据第一关键字的顺序排出sa数组的顺序 for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1; i<n; i++) //更新x数组 x为rank数组 x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++; } return ; } int h[maxn];//也就是排名相邻的两个后缀的最长公共前缀sa[i]和sa[i-1] int Rank[maxn];//名次数组 void get_height(int *r,int *sa,int n) { int k=0,i,j; for(int i=1; i<=n; i++) Rank[sa[i]]=i; for(int i=0; i<n; h[Rank[i++]]=k) for(k?k--:0,j=sa[Rank[i]-1]; r[i+k]==r[j+k]; k++) ; return ; } int a[maxn]; int sa[maxn],r[maxn]; int judge(int mid) { int mn,mx,j; for(int i=1; i<=n; i=j) { while(i<=n&&h[i]<mid)//排除最长前缀小于mid的 i++; j=i; mn=n;//记录同一组中sa的最小值 mx=0;//记录同一组中sa的最大值 if(i==n+1) break; mn=min(mn,sa[i-1]); mx=max(mx,sa[i-1]); while(j<=n&&h[j]>=mid)//大于mid的分在同一组 { mn=min(mn,sa[j]); mx=max(mx,sa[j]); j++; } if(mx-mn>=mid)//如果不重复返回1 return 1; } return 0; } int main() { while(~scanf("%d",&n)&&n) { for(int i=0; i<n; i++) scanf("%d",&a[i]); for(int i=0; i<n-1; i++) { a[i]=a[i+1]-a[i]+89; } n--; a =0; da(a,sa,n+1,180); get_height(a,sa,n); int l=0; int R=n-1; while(l<=R)//二分枚举长度 { int mid=(l+R)>>1; if(judge(mid)) l=mid+1; else R=mid-1; } int ans=R; if(ans>=4) printf("%d\n",ans+1); else printf("0\n"); } }
相关文章推荐
- Poj 1743 Musical Theme (后缀数组 不可重叠最长重复子串)
- poj 1743 男人八题之后缀数组求最长不可重叠最长重复子串
- poj 1743 男人八题之后缀数组求最长不可重叠最长重复子串
- poj 1743 字符串 后缀数组 不可重叠最长重复子串
- 【后缀数组】不可重叠最长重复子串
- 后缀数组模版 及 可重叠和不可重叠最长重复子串【for_wind】
- 【后缀数组】不可重叠最长重复子串
- POJ 1743 Musical Theme(后缀数组[不可重叠最长重复子串])
- poj 1743 Musical Theme (后缀数组 不可重叠最长重复子串)
- 【后缀数组求不可重叠最长重复子串】POJ 1743
- PKU1743(Musical Theme)求不可重叠最长重复子串(后缀数组+二分)
- POJ 1743 Musical Theme(后缀数组求不可重叠最长重复子串)
- POJ 1743 Musical Theme(不可重叠最长重复子串 后缀数组)
- poj1743 Musical Theme(后缀数组--不可重叠最长重复子串+二分)
- 后缀数组 最长不可重叠重复子串问题
- poj1743(后缀数组+二分--不可重叠最长重复子串)
- 不可重叠的最长重复子串(后缀数组)
- poj1743 后缀数组求不可重叠的重复出现的子串最长长度
- POJ 1743 Musical Theme 后缀数组 不可重叠最长重复子串
- POJ 1743 Musical Theme (后缀数组加二分求不可重叠最长重复子串)