题意:
给定一个字符串,求至少出现k 次的最长重复子串,这k 个子串可以重叠。
分析:
先二分答案,然后将后缀分成若干组。
不同的是,这里要判断的是有没有一个组的后缀个数不小于k。
如果有,那么存在k 个相同的子串满足条件,否则不存在。这个做法的时间复杂度为O(nlogn)。
// File Name: 3261.cpp // Author: Zlbing // Created Time: 2013年09月04日 星期三 21时21分51秒 #include<iostream> #include<string> #include<algorithm> #include<cstdlib> #include<cstdio> #include<set> #include<map> #include<vector> #include<cstring> #include<stack> #include<cmath> #include<queue> using namespace std; #define CL(x,v); memset(x,v,sizeof(x)); #define INF 0x3f3f3f3f #define LL long long #define REP(i,r,n) for(int i=r;i<=n;i++) #define RREP(i,n,r) for(int i=n;i>=r;i--) //rank从0开始 //sa从1开始,因为最后一个字符(最小的)排在第0位 //height从2开始,因为表示的是sa[i-1]和sa[i] const int MAXN=1e6+100; int rank[MAXN],sa[MAXN],X[MAXN],Y[MAXN],height[MAXN],s[MAXN]; int buc[MAXN]; void calheight(int n) { int i , j , k = 0; for(i = 1 ; i <= n ; i++) rank[sa[i]] = i; for(i = 0 ; i < n ; height[rank[i++]] = k) for(k?k--:0 , j = sa[rank[i]-1] ; s[i+k] == s[j+k] ; k++); } bool cmp(int *r,int a,int b,int l) { return (r[a] == r[b] && r[a+l] == r[b+l]); } void suffix(int n,int m = 128) { int i , l , p , *x = X , *y = Y; for(i = 0 ; i < m ; i ++) buc[i] = 0; for(i = 0 ; i < n ; i ++) buc[ x[i] = s[i] ] ++; for(i = 1 ; i < m ; i ++) buc[i] += buc[i-1]; for(i = n - 1; i >= 0 ; i --) sa[ --buc[ x[i] ]] = i; for(l = 1,p = 1 ; p < n ; m = p , l *= 2) { p = 0; for(i = n-l ; i < n ; i ++) y[p++] = i; for(i = 0 ; i < n ; i ++) if(sa[i] >= l) y[p++] = sa[i] - l; for(i = 0 ; i < m ; i ++) buc[i] = 0; for(i = 0 ; i < n ; i ++) buc[ x[y[i]] ] ++; for(i = 1 ; i < m ; i ++) buc[i] += buc[i-1]; for(i = n - 1; i >= 0 ; i --) sa[ --buc[ x[y[i]] ] ] = y[i]; for(swap(x,y) , x[sa[0]] = 0 , i = 1 , p = 1 ; i < n ; i ++) x[ sa[i] ] = cmp(y,sa[i-1],sa[i],l) ? p-1 : p++; } calheight(n-1);//后缀数组关键是求出height,所以求sa的时候顺便把rank和height求出来 } int n,k; bool judge(int x) { int cnt=1; for(int i=2;i<=n;i++) { if(height[i]>=x) cnt++; else cnt=1; if(cnt>=k) return true; } return false; } int main() { while(~scanf("%d%d",&n,&k)) { REP(i,0,n-1) scanf("%d",&s[i]); REP(i,0,n-1)s[i]++; s[n]=0; suffix(n+1,1000002); int l=0,r=n,mid; int ans=-1; while(l<=r) { mid=l+(r-l+1)/2; if(judge(mid)) { ans=max(mid,ans); l=mid+1; } else r=mid-1; } printf("%d ",ans); } return 0; }