水题不好意思说题解。
说说题意吧:
给一个字符串(数字串),然后求最长k次重复子串。
即某串在字符串中重复了至少k次,求这种串的最长长度。
代码:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 21000
using namespace std;
struct LSH
{
int x,id;
bool operator < (const LSH &a)const{return x<a.x;}
}lsh[N];
int s[N];
int sa[N],rank[N],h[N],n,m,len;
int cnt[N],val[N],stk[N],_val[N],top;
bool issame(int a,int b,int hl)
{
return val[a]==val[b]&&
((a+hl>=len&&b+hl>=len)||(a+hl<len&&b+hl<len&&val[a+hl]==val[b+hl]));
}
void SA(int lim)
{
int i,j,k,hl;
for(i=0;i<lim;i++)cnt[i]=0;
for(i=0;i<len;i++)cnt[val[i]=s[i]]++;
for(i=1;i<lim;i++)cnt[i]+=cnt[i-1];
for(i=len-1;i>=0;i--)sa[--cnt[val[i]]]=i;
for(k=1;;k++)
{
top=0,hl=1<<(k-1);
for(i=0;i<len;i++)if(sa[i]+hl>=len)stk[top++]=sa[i];
for(i=0;i<len;i++)if(sa[i]>=hl)stk[top++]=sa[i]-hl;
for(i=0;i<lim;i++)cnt[i]=0;
for(i=0;i<len;i++)cnt[val[i]]++;
for(i=1;i<lim;i++)cnt[i]+=cnt[i-1];
for(i=len-1;i>=0;i--)sa[--cnt[val[stk[i]]]]=stk[i];
for(lim=i=0;i<len;lim++)
{
for(j=i;j<len-1&&issame(sa[j],sa[j+1],hl);j++);
for(;i<=j;i++)_val[sa[i]]=lim;
}
for(i=0;i<len;i++)val[i]=_val[i];
if(lim==len)break;
}
for(i=0;i<len;i++)rank[sa[i]]=i;
for(k=i=0;i<len;i++)
{
if(k)k--;
if(!rank[i])continue;
while(s[i+k]==s[sa[rank[i]-1]+k])k++;
h[rank[i]]=k;
}
}
int K;
bool check(int mid)
{
int num=1,i;
for(i=0;i<len;i++)
{
if(h[i]>=mid)num++;
else num=1;
if(num>=K)return 1;
}
return 0;
}
int main()
{
// freopen("test.in","r",stdin);
int i,j,k;
while(scanf("%d%d",&len,&K)!=EOF)
{
for(i=0;i<len;i++)scanf("%d",&lsh[i].x),lsh[i].id=i;
sort(lsh,lsh+len);
int nm=0;
for(i=0;i<len;i++)
{
if(i==0||lsh[i].x!=lsh[i-1].x)nm++;
s[lsh[i].id]=nm;
}
SA(20000);
int l=0,r=len,mid,ans=0;
while(l<=r)
{
if(r-l<=3)
{
for(i=l;i<=r;i++)if(check(i))ans=i;
break;
}
mid=l+r>>1;
if(check(mid))l=mid;
else r=mid;
}
printf("%d\n",ans);
}
return 0;
}