题意:找出出现k次的可重叠的最长子串的长度。
/* 求出height数组,二分答案,将height分组,看有没有一组个数大于K。 WA了很多遍,最后看别人的题解,发现往字符串后面填了一个0,就可以AC了,不知道为什么。 */ #include<cstdio> #include<iostream> #include<algorithm> #define N 100010 using namespace std; int s[N],sa[N],rk[N],ht[N],t1[N],t2[N],c[N],n,K; struct node{ int x,id; bool operator<(const node&a)const{ if(x==a.x) return id<a.id; return x<a.x; } }r[N]; bool cmp(int *y,int a,int b,int k){ int a1=y[a],b1=y[b]; int a2=a+k<n?y[a+k]:-1; int b2=b+k<n?y[b+k]:-1; return a1==b1&&a2==b2; } void DA(){ int *x=t1,*y=t2,m=1;n++; sort(r,r+n); for(int i=0;i<n;i++) sa[i]=r[i].id; x[sa[0]]=0; for(int i=1;i<n;i++) x[sa[i]]=(r[i].x==r[i-1].x?m-1:m++); for(int k=1,p=0;k<=n;k*=2,m=p,p=0){ for(int i=n-k;i<n;i++) y[p++]=i; for(int i=0;i<n;i++) if(sa[i]>=k) y[p++]=sa[i]-k; for(int i=0;i<m;i++) c[i]=0; for(int i=0;i<n;i++) c[x[y[i]]]++; for(int i=1;i<m;i++) c[i]+=c[i-1]; for(int i=n-1;~i;i--) sa[--c[x[y[i]]]]=y[i]; swap(x,y);p=1;x[sa[0]]=0; for(int i=1;i<n;i++) if(cmp(y,sa[i-1],sa[i],k)) x[sa[i]]=p-1; else x[sa[i]]=p++; if(p>=n) break; } for(int i=0;i<n;i++) rk[sa[i]]=i;n--; } void get_ht(){ for(int i=0,k=0;i<n;ht[rk[i++]]=k){ int j=sa[rk[i]-1];k=k?k-1:0; while(s[i+k]==s[j+k]) k++; } } bool check(int mid){ int cnt=0; for(int i=1;i<=n;i++){ if(ht[i]<mid) cnt=1; else cnt++; if(cnt>=K) return true; } return false; } int main(){ while(scanf("%d%d",&n,&K)!=EOF){ for(int i=0;i<n;i++) { scanf("%d",&s[i]); r[i].x=s[i]+1;r[i].id=i; } r[n].x=0,r[n].id=n; DA();get_ht(); 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; }
时间: 2024-10-27 13:57:15