字符串 后缀数组(可重叠的k 次最长重复子串)poj 3261
开始用起了后缀数组这种高级的东西,虽然细节方面是勉强看懂了,但是能运用好就行
要是有做这套题的朋友实在是不得其解的话,去看看这篇论文吧。。
IOI2009 国家集训队论文后缀数组罗穗骞
height数组当中存了从第一名到最后一名的公共前缀的长度
height 数组:定义height[i]=suffix(sa[i-1])和suffix(sa[i])的最长公共前缀,也就是排名相邻的两个后缀的最长公共前缀。那么对于j 和k,不妨设
rank[j]<rank[k],则有以下性质:
suffix(j) 和suffix(k) 的最长公共前缀为height[rank[j]+1],height[rank[j]+2], height[rank[j]+3], … ,height[rank[k]]中的最小值。
那么此题我们可以二分枚举其中的答案。
代码如下:
View Code
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<cstdlib> 5 #include<algorithm> 6 #include<cmath> 7 using std::sort; 8 int const M = 1001000; 9 int const N = 20100; 10 int rank[N],wb[M],wv[M],ws[M],height[N],num[N],sa[N]; 11 int n,k; 12 int cmp(int *r,int a,int b,int l) 13 { 14 return r[a]==r[b]&&r[a+l]==r[b+l]; 15 } 16 void da(int *r,int *sa,int n,int m) 17 { 18 int i,j,p,*x=rank,*y=wb,*t; 19 for(i=0; i<m; i++) ws[i]=0; 20 for(i=0; i<n; i++) ws[x[i]=r[i]]++; 21 for(i=1; i<m; i++) ws[i]+=ws[i-1]; 22 for(i=n-1; i>=0; i--) sa[--ws[x[i]]]=i; 23 for(j=1,p=1; p<n; j*=2,m=p) 24 { 25 for(p=0,i=n-j; i<n; i++) y[p++]=i; 26 for(i=0; i<n; i++) if(sa[i]>=j) y[p++]=sa[i]-j; 27 for(i=0; i<n; i++) wv[i]=x[y[i]]; 28 for(i=0; i<m; i++) ws[i]=0; 29 for(i=0; i<n; i++) ws[wv[i]]++; 30 for(i=1; i<m; i++) ws[i]+=ws[i-1]; 31 for(i=n-1; i>=0; i--) sa[--ws[wv[i]]]=y[i]; 32 for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1; i<n; i++) 33 x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++; 34 } 35 return; 36 } 37 38 void calheight(int *r,int *sa,int n) 39 { 40 int i,j,k=0; 41 for(i=1; i<=n; i++) rank[sa[i]]=i; 42 for(i=0; i<n; height[rank[i++]]=k) 43 for(k?k--:0,j=sa[rank[i]-1]; r[i+k]==r[j+k]; k++); 44 return; 45 } 46 bool check(int len) 47 { 48 int tot=0; 49 for(int i=2;i<=n;i++) 50 { 51 if(height[i]<len)tot=0; 52 else 53 { 54 tot++; 55 if(tot==k-1)return true; 56 } 57 } 58 return false; 59 } 60 int main() 61 { 62 while(~scanf("%d %d",&n,&k)) 63 { 64 for(int i=0;i<n;i++) 65 { 66 scanf("%d",&num[i]); 67 } 68 da(num,sa,n+1,M); 69 calheight(num,sa,n); 70 int ans=0; 71 int l=0,r=n; 72 while(l<=r) 73 { 74 int m=(l+r)>>1; 75 if(check(m)) 76 l=m+1,ans=m; 77 else 78 r=m-1; 79 } 80 printf("%d\n",ans); 81 } 82 return 0; 83 }