题意就是给一列数字,求最长的一个子串,并且满足子串在原数串中出现至少K次,子串可以重叠。
解法是将问题转为判定性问题,二分子串的长度,判定是否满足重复至少K次。判定方法是经典的根据子串长度将Height数组分组,看某一分组是否至少含有K个元素。
1 #include <iostream> 2 #include <vector> 3 #include <algorithm> 4 #include <string> 5 #include <string.h> 6 #include <stdio.h> 7 #include <queue> 8 #include <stack> 9 #include <map> 10 #include <set> 11 #include <cmath> 12 #include <ctime> 13 #include <cassert> 14 #include <sstream> 15 using namespace std; 16 17 const int N=2e6+110; 18 19 int sa[N]; 20 int t1[N],t2[N],c[N]; 21 int rk[N],height[N]; 22 23 inline int cmp(int *r,int a,int b,int l){ 24 return r[a]==r[b]&&r[a+l]==r[b+l]; 25 } 26 int s[N]; 27 void calcSA (int *s,int n,int m) { 28 int i,j,p,*x=t1,*y=t2; 29 for(i=0;i<m;i++)c[i]=0; 30 for(i=0;i<n;i++)c[x[i]=s[i]]++; 31 for(i=1;i<m;i++)c[i]+=c[i-1]; 32 for(i=n-1;i>=0;i--)sa[--c[x[i]]]=i; 33 for(j=1;j<=n;j<<=1){ 34 p=0; 35 for(i=n-j;i<n;i++)y[p++]=i; 36 for(i=0;i<n;i++)if(sa[i]>=j)y[p++]=sa[i]-j; // 排名从小到大,如果pos比j大,则suffix(sa[i]-j)的第二关键字为p 37 for(i=0;i<m;i++)c[i]=0; 38 for(i=0;i<n;i++)c[x[y[i]]]++; 39 for(i=1;i<m;i++)c[i]+=c[i-1]; 40 for(i=n-1;i>=0;i--)sa[--c[x[y[i]]]]=y[i]; // 根据第二关键字从大到小,确定新一轮sa 41 swap(x,y); 42 p=1;x[sa[0]]=0; 43 for(i=1;i<n;i++) 44 x[sa[i]]=cmp(y,sa[i-1],sa[i],j)?p-1:p++; 45 if(p>=n)break; 46 m=p; 47 } 48 } 49 50 void calcHeight(int *s,int n) { 51 int i,j,k=0; 52 for(i=0;i<=n;i++)rk[sa[i]]=i; 53 for(i=0;i<n;i++){ 54 if(k)k--; // h[i]>=h[i-1]-1 55 j=sa[rk[i]-1]; // suffix(j)排名在suffix(i)前一位 56 while(s[i+k]==s[j+k])k++; // 暴力计算lcp 57 height[rk[i]]=k; 58 } 59 } 60 61 62 bool ok(int n,int m,int k) { 63 int cnt=1; 64 for (int i=1;i<=n;i++) { 65 if (height[i]<m) { 66 cnt=1; 67 } 68 else { 69 cnt++; 70 if (cnt>=k) return true; 71 } 72 } 73 return false; 74 } 75 int main () { 76 int n,k; 77 while (scanf("%d %d",&n,&k)!=EOF) { 78 int mx=0; 79 for (int i=0;i<n;i++) { 80 scanf("%d",s+i); 81 mx=max(mx,s[i]); 82 } 83 s[n]=0; 84 calcSA(s,n+1,mx+10); 85 calcHeight(s,n); 86 int l=0,r=n,ret=0; 87 while (l<=r) { 88 int m=(l+r)>>1; 89 if (ok(n,m,k)) { 90 ret=m; 91 l=m+1; 92 } 93 else r=m-1; 94 } 95 cout<<ret<<endl; 96 } 97 return 0; 98 }