后缀思想及解法的来源:http://wenku.baidu.com/link?url=kG_SolxPKmyHjwKCvnQ5bxVMUAA3FU-3HFSBASW_jLSgku9u9r9PKHKGqf4CF9RTxG4gfkYg6lMCdGZu2eVMCvidEtcObiAXLP_9-3PhKp3
思路:这题的做法和POJ 1743差不多,也是先二分答案,然后将后缀分成若干组。不同的是,这里要判断的是有没有一个组的后缀个数不小于k。如果有,那么存在k个相同的子串满足条件,否则不存在。这个做法的时间复杂度为O(nlogn)。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<map>
#include<queue>
#include<set>
#include<cmath>
#include<bitset>
#define mem(a,b) memset(a,b,sizeof(a))
#define lson i<<1,l,mid
#define rson i<<1|1,mid+1,r
#define llson j<<1,l,mid
#define rrson j<<1|1,mid+1,r
#define INF 0x7fffffff
#define maxn 20010
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
void radix(int *str,int *a,int *b,int n,int m)
{
static int count[maxn*2];
mem(count,0);
for(int i=0;i<n;i++) ++count[str[a[i]]];
for(int i=1;i<=m;i++) count[i]+=count[i-1];
for(int i=n-1;i>=0;i--) b[--count[str[a[i]]]]=a[i];
}
void suffix(int *str,int *sa,int n,int m) //倍增算法计算出后缀数组sa
{
static int rank[maxn*2],a[maxn*2],b[maxn*2];
for(int i=0;i<n;i++) rank[i]=i;
radix(str,rank,sa,n,m);
rank[sa[0]]=0;
for(int i=1;i<n;i++)
rank[sa[i]]=rank[sa[i-1]]+(str[sa[i]]!=str[sa[i-1]]);
for(int i=0;1<<i<n;i++)
{
for(int j=0;j<n;j++)
{
a[j]=rank[j]+1;
b[j]=j+(1<<i)>=n?0:rank[j+(1<<i)]+1;
sa[j]=j;
}
radix(b,sa,rank,n,n);
radix(a,rank,sa,n,n);
rank[sa[0]]=0;
for(int j=1;j<n;j++)
rank[sa[j]]=rank[sa[j-1]]+(a[sa[j-1]]!=a[sa[j]]||b[sa[j-1]]!=b[sa[j]]);
}
}
void calcHeight(int *str,int *sa,int *h,int n) //求出最长公共前缀数组h
{
static int rank[maxn*2];
int k=0;
h[0]=0;
for(int i=0;i<n;i++) rank[sa[i]]=i;
for(int i=0;i<n;i++)
{
k=k==0?0:k-1;
if(rank[i])
while(str[i+k]==str[sa[rank[i]-1]+k]) k++;
else k=0;
h[rank[i]]=k;
}
}
int a[maxn],sa[maxn],height[maxn];
bool binary(int mid,int n,int k)
{
int i=1;
while(1)
{
while(i<n&&height[i]<mid) i++;
if(i==n) break;
int cnt=1; //>=mid分在一组
while(i<n&&height[i]>=mid) cnt++,i++;
if(cnt>=k) return true;
}
return false;
}
int main()
{
//freopen("test.txt","r",stdin);
int n,k,i;
while(~scanf("%d%d",&n,&k))
{
for(i=0;i<n;i++)
scanf("%d",a+i);
suffix(a,sa,n,20000);
calcHeight(a,sa,height,n);
//for(i=1;i<=n;i++)
// cout<<height[i]<<' '<<sa[i]<<endl;
int l=1,r=n,mid,ans=0;
while(l<=r)
{
mid=(l+r)>>1;
if(binary(mid,n,k)) ans=mid,l=mid+1;
else r=mid-1;
}
printf("%d\n",ans);
}
return 0;
}