题意:
最长的出现k次的重复(可重叠)子串
题解:
和POJ 1743一样,稍作改变,求最大的话一般都是对后缀数组二分处理。。
http://www.cnblogs.com/proverbs/archive/2013/02/05/2893419.html
判定条件从位置相差>=m改为是否存在一个块内后缀的个数大于等于m
数比较大,快排搞定,好像基数排序也可以。
1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 #include <cstdlib> 5 #include <algorithm> 6 7 #define N 50500 8 9 using namespace std; 10 11 int r[N],wa[N],wc[N],wv[N],sa[N],wb[N],height[N],rank[N]; 12 int n,m; 13 14 inline bool cmp1(int a,int b) 15 { 16 if(r[a]==r[b]) return a<b; 17 return r[a]<r[b]; 18 } 19 20 inline bool cmp2(int a,int b) 21 { 22 if(wv[a]==wv[b]) return a<b; 23 return wv[a]<wv[b]; 24 } 25 26 inline bool cmp(int *r,int a,int b,int l) 27 { 28 return r[a]==r[b]&&r[a+l]==r[b+l]; 29 } 30 31 inline void da(int *r,int *sa,int n,int m) 32 { 33 int i,j,p,*x=wa,*y=wb,*t; 34 for(i=0;i<n;i++) wc[i]=i,x[i]=r[i]; 35 sort(wc,wc+n,cmp1); 36 for(i=0;i<n;i++) sa[i]=wc[i]; 37 for(j=1,p=1;p<n;j<<=1,m=p) 38 { 39 for(i=n-j,p=0;i<n;i++) y[p++]=i; 40 for(i=0;i<n;i++) if(sa[i]>=j) y[p++]=sa[i]-j; 41 for(i=0;i<n;i++) wv[i]=x[y[i]]; 42 for(i=0;i<n;i++) wc[i]=i; 43 sort(wc,wc+n,cmp2); 44 for(i=0;i<n;i++) sa[i]=y[wc[i]]; 45 for(t=x,x=y,y=t,p=1,x[sa[0]]=0,i=0;i<n;i++) 46 x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++; 47 } 48 } 49 50 inline void getheight(int *r,int *sa,int n) 51 { 52 int i,j,k=0; 53 for(i=1;i<=n;i++) rank[sa[i]]=i; 54 for(i=0;i<n;height[rank[i++]]=k) 55 for(k?k--:0,j=sa[rank[i]-1];r[i+k]==r[j+k];k++); 56 } 57 58 inline bool check(int x) 59 { 60 int cnt=1; 61 for(int i=1;i<=n;i++) 62 { 63 if(height[i]<x) cnt=1; 64 else cnt++; 65 if(cnt>=m) return true; 66 } 67 return false; 68 } 69 70 inline void getans() 71 { 72 int l=1,r=n,mid,res; 73 while(l<=r) 74 { 75 mid=(l+r)>>1; 76 if(check(mid)) res=mid,l=mid+1; 77 else r=mid-1; 78 } 79 printf("%d\n",res); 80 } 81 82 inline void go() 83 { 84 for(int i=0;i<n;i++) scanf("%d",&r[i]); 85 r[n]=0; 86 da(r,sa,n+1,1000010); 87 getheight(r,sa,n); 88 getans(); 89 } 90 91 int main() 92 { 93 while(scanf("%d%d",&n,&m)!=EOF) go(); 94 return 0; 95 }