【题意】
求重复k次可重叠子串长度
【分析】
height分组,一组内有k个后缀即可
【代码】
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<algorithm> using namespace std; const int maxn=2e4+5; const int maxm=1e6+5; int n,k; int a[maxn],h[maxn],maxi,id[maxn]; int sa[maxn],rk[maxn],oldrk[maxn],cnt[maxn],fz[maxn]; bool cmp(int x,int y,int w) { return oldrk[x]==oldrk[y] && oldrk[x+w]==oldrk[y+w]; } void calcsa() { int m=maxi; for(int i=0;i<=m;i++) cnt[i]=0; for(int i=1;i<=n;i++) cnt[rk[i]=a[i]]++; for(int i=1;i<=m;i++) cnt[i]+=cnt[i-1]; for(int i=n;i>=1;i--) sa[cnt[rk[i]]--]=i; int i,p; for(int w=1;;w<<=1,m=p) { for(p=0,i=n;i>n-w;i--) id[++p]=i; for(i=1;i<=n;i++) if(sa[i]>w) id[++p]=sa[i]-w; for(i=0;i<=m;i++) cnt[i]=0; for(i=1;i<=n;i++) cnt[fz[i]=rk[id[i]]]++; for(i=1;i<=m;i++) cnt[i]+=cnt[i-1]; for(i=n;i>=1;i--) sa[cnt[fz[i]]--]=id[i]; for(i=1;i<=n;i++) oldrk[i]=rk[i]; for(p=0,i=1;i<=n;i++) rk[sa[i]]=cmp(sa[i],sa[i-1],w)?p:++p; if(p==n) { for(i=1;i<=n;i++) sa[rk[i]]=i; break; } } } void calch() { int i,k=0; for(i=1;i<=n;i++) { if(k) k--; while(a[i+k]==a[sa[rk[i]-1]+k]) k++; h[rk[i]]=k; } } bool check(int x) { int cnt=1; for(int i=1;i<=n;i++) { if(h[i]>=x) cnt++; else cnt=1; if(cnt>=k) return 1; } return 0; } int main() { freopen("a.in","r",stdin); freopen("a.out","w",stdout); scanf("%d%d",&n,&k); for(int i=1;i<=n;i++) scanf("%d",&a[i]),maxi=max(maxi,a[i]); calcsa(); calch(); int l=0,r=n,ans; while(l<=r) { int mid=l+r>>1; if(check(mid)) ans=mid,l=mid+1; else r=mid-1; } printf("%d\n",ans); return 0; }