后缀数组求最长k次重复子串。
求完height数组之后倍增答案。
check的时候枚举height数组。
如果连续cnt个height都大于等于某长度ans,且cnt不小于题目要求的k次重复,则ans为一个合法答案。
如果枚举过程中遇到了小于ans的height,则需要重置计数器cnt(初值为1)。
注意考虑每个数组分别需要开多大。
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 using namespace std; 5 6 int n,m,ans; 7 int s[20005]; 8 int sa[20005],rk[20005]; 9 int h[1000005],tr[1000005]; 10 11 int cmp(int x,int y,int k) 12 { 13 if(x+k>n||y+k>n)return 0; 14 return rk[x]==rk[y]&&rk[x+k]==rk[y+k]; 15 } 16 17 void cal() 18 { 19 int i,cnt; 20 for(i=1;i<=n;i++)h[s[i]]++; 21 for(i=1,cnt=0;i<=1000000;i++)if(h[i])tr[i]=++cnt; 22 for(i=1;i<=1000000;i++)h[i]+=h[i-1]; 23 for(i=1;i<=n;i++)rk[i]=tr[s[i]],sa[h[s[i]]--]=i; 24 for(int k=1;cnt!=n;k<<=1) 25 { 26 for(i=1;i<=n;i++)h[i]=0; 27 for(i=1;i<=n;i++)h[rk[i]]++; 28 for(i=1;i<=n;i++)h[i]+=h[i-1]; 29 for(i=n;i;i--)if(sa[i]>k)tr[sa[i]-k]=h[rk[sa[i]-k]]--; 30 for(i=1;i<=k;i++)tr[n-i+1]=h[rk[n-i+1]]--; 31 for(i=1;i<=n;i++)sa[tr[i]]=i; 32 for(i=1,cnt=0;i<=n;i++)tr[sa[i]]=cmp(sa[i],sa[i-1],k)?cnt:++cnt; 33 for(i=1;i<=n;i++)rk[i]=tr[i]; 34 } 35 for(i=1;i<=n;i++)h[i]=0; 36 for(i=1;i<=n;i++) 37 { 38 if(rk[i]==1)continue; 39 for(int j=max(1,h[rk[i-1]]-1);;j++) 40 { 41 if(s[i+j-1]==s[sa[rk[i]-1]+j-1])h[rk[i]]=j; 42 else break; 43 } 44 } 45 } 46 47 int check(int k) 48 { 49 if(k>n)return 0; 50 int cnt=1; 51 for(int i=2;i<=n;i++) 52 { 53 if(h[i]>=k)cnt++; 54 else cnt=1; 55 if(cnt>=m)return 1; 56 } 57 return 0; 58 } 59 60 int main() 61 { 62 scanf("%d%d",&n,&m); 63 for(int i=1;i<=n;i++)scanf("%d",&s[i]); 64 cal(); 65 for(int i=20;i>=0;i--) 66 if(check(ans|(1<<i)))ans|=(1<<i); 67 printf("%d",ans); 68 return 0; 69 }