poj3261 Milk Patterns 后缀数组求可重叠的k次最长重复子串
题目链接:http://poj.org/problem?id=3261
思路:
后缀数组的很好的一道入门题目
先利用模板求出sa数组和height数组
然后二分答案(即对于可能出现的重复长度进行二分) ,二分的时候,对 height进行分组,看是否存在一组height值使得其重复的次数大于等于k
代码如下:
1 #include<iostream> 2 #include<cstdlib> 3 #include<cstdio> 4 #include<cstring> 5 using namespace std; 6 #define maxn 20010 7 int wa[maxn],wb[maxn],wv[maxn],wq[maxn]; 8 int rank[maxn],sa[maxn]; 9 int r[maxn]; 10 int height[maxn]; 11 int s[maxn]; 12 int n,k; 13 int cmp(int *r,int a,int b,int l) 14 { 15 return r[a]==r[b]&&r[a+l]==r[b+l]; 16 } 17 void da(int *r,int *sa,int n,int m) 18 { 19 int i,j,p,*x=wa,*y=wb,*t; 20 for(i=0;i<m;i++) wq[i]=0; 21 for(i=0;i<n;i++) wq[x[i]=r[i]]++; 22 for(i=1;i<m;i++) wq[i]+=wq[i-1]; 23 for(i=n-1;i>=0;i--) sa[--wq[x[i]]]=i; 24 25 for(j=1,p=1;p<n;j*=2,m=p) 26 { 27 for(p=0,i=n-j;i<n;i++) y[p++]=i; 28 for(i=0;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j; 29 for(i=0;i<n;i++) wv[i]=x[y[i]]; 30 for(i=0;i<m;i++) wq[i]=0; 31 for(i=0;i<n;i++) wq[wv[i]]++; 32 for(i=1;i<m;i++) wq[i]+=wq[i-1]; 33 for(i=n-1;i>=0;i--) sa[--wq[wv[i]]]=y[i]; 34 for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=1;i<n;i++) 35 x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++; 36 } 37 return ; 38 } 39 void callheight(int *r,int n) 40 { 41 int i,j,k=0; 42 for(i=1;i<=n;i++) rank[sa[i]]=i; 43 for(i=0;i<n;i++) 44 { 45 if(k) k--; 46 j=sa[rank[i]-1]; 47 while(r[i+k]==r[j+k]) k++; 48 height[rank[i]]=k; 49 } 50 } 51 bool check(int n,int mid) 52 { 53 int num=1; 54 for(int i=2;i<=n;i++) 55 { 56 if(height[i]>=mid) 57 { 58 num++; 59 if(num>=k) 60 return 1; 61 } 62 else num=1; 63 } 64 return 0; 65 } 66 int main() 67 { 68 while(scanf("%d%d",&n,&k)!=EOF) 69 { 70 int Maxx=0; 71 for(int i=0;i<n;i++) 72 { 73 scanf("%d",&s[i]); 74 Maxx=max(Maxx,s[i]); 75 } 76 77 s[n]=0; 78 da(s,sa,n+1,Maxx+1); 79 callheight(s,n); 80 81 int low=1,high=n-1; 82 int ans=0; 83 while(low<=high) 84 { 85 int mid=(low+high)/2; 86 if(check(n,mid)) 87 { 88 ans=mid; 89 low=mid+1; 90 } 91 else high=mid-1; 92 } 93 94 cout<<ans<<endl; 95 96 } 97 return 0; 98 99 }