描述
小Hi平时的一大兴趣爱好就是演奏钢琴。我们知道一个音乐旋律被表示为长度为 N 的数构成的数列。小Hi在练习过很多曲子以后发现很多作品中的旋律有重复的部分。
我们把一段旋律称为(k,l)-重复的,如果它满足由一个长度为l的字符串重复了k次组成。 如旋律abaabaabaaba是(4,3)重复的,因为它由aba重复4次组成。
小Hi想知道一部作品中k最大的(k,l)-重复旋律。
输入
一行一个仅包含小写字母的字符串。字符串长度不超过 100000。
输出
一行一个整数,表示答案k。
- Sample Input
- babbabaabaabaabab
- Sample Output
- 4
- 假如循环节长度为L
- 如果求出了后缀i和i+L的lcp
- 那么重复次数k=lcp(i,i+L)/L+1
- 那么O(n^2)的暴力有了,枚举L和i,计算k更新最大值
- 但是枚举i可以只枚举L的倍数,算出k
- 对于i和i+L,最多只会相差1
- 如果最优串的开始位置恰好在L的倍数上,那我们找到的最大的k就是正确答案
- 如果不在L的倍数上,那么最优的开始位置肯定在(i-L,i)上
- 如果lcp模L有余数,说明前面还需要补上L-lcp%L位,如果可行答案可以加1
- 于是可以判断开始位置为i-L+lcp%L与i+lcp%L的lcp
- 如果构成重复,那么算出来的
- k=lcp(i-L+lcp%L,i+lcp%L)/L+1=[lcp(i,i+L)/L+1]+1,比开始位置为i要好
- 于是复杂度:
- $O(\frac{n}{1}+\frac{n}{2}+\frac{n}{3}+...\frac{n}{n})$
- $=O(nlogn)$
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 #include<cmath> 6 using namespace std; 7 int n,m,c[200001],x[200001],y[200001],SA[200001],s[200001],rk[200001],h[200001]; 8 int Min[200001][21],Log[200001],ans; 9 char ch[200001]; 10 void radix_sort() 11 {int i; 12 for (i=0;i<=m;i++) 13 c[i]=0; 14 for (i=1;i<=n;i++) 15 c[x[y[i]]]++; 16 for (i=2;i<=m;i++) 17 c[i]+=c[i-1]; 18 for (i=n;i>=1;i--) 19 SA[c[x[y[i]]]--]=y[i]; 20 } 21 void build_SA() 22 {int i,j,k,p; 23 for (i=1;i<=n;i++) 24 x[i]=s[i],y[i]=i; 25 m=100000; 26 radix_sort(); 27 for (k=1;k<=n;k<<=1) 28 { 29 p=0; 30 for (i=n-k+1;i<=n;i++) 31 y[++p]=i; 32 for (i=1;i<=n;i++) 33 if (SA[i]>k) y[++p]=SA[i]-k; 34 radix_sort(); 35 p=1;swap(x,y); 36 x[SA[1]]=1; 37 for (i=2;i<=n;i++) 38 x[SA[i]]=((y[SA[i]]==y[SA[i-1]])&&(y[SA[i]+k]==y[SA[i-1]+k]))?p:++p; 39 if (p>=n) break; 40 m=p; 41 } 42 for (i=1;i<=n;i++) 43 rk[SA[i]]=i; 44 int L=0; 45 for (i=1;i<=n;i++) 46 { 47 if (L>0) L--; 48 j=SA[rk[i]-1]; 49 while (i+L<=n&&j+L<=n&&(s[j+L]==s[i+L])) L++; 50 h[rk[i]]=L; 51 } 52 } 53 int rmq(int x,int y) 54 { 55 int L=Log[y-x+1]; 56 return min(Min[x][L],Min[y-(1<<L)+1][L]); 57 } 58 int lcp(int x,int y) 59 { 60 if (rk[x]>rk[y]) swap(x,y); 61 return rmq(rk[x]+1,rk[y]); 62 } 63 int main() 64 {int i,j,L; 65 scanf("%s",ch); 66 n=strlen(ch); 67 for (i=1;i<=n;i++) 68 { 69 s[i]=ch[i-1]-‘a‘+1; 70 } 71 build_SA(); 72 memset(Min,127/2,sizeof(Min)); 73 for (i=1;i<=n;i++) 74 Min[i][0]=h[i]; 75 Log[1]=0; 76 for (i=2;i<=n;i++) 77 Log[i]=Log[i/2]+1; 78 for (j=1;(1<<j)<=n;j++) 79 { 80 for (i=1;i<=n-(1<<j)+1;i++) 81 Min[i][j]=min(Min[i][j-1],Min[i+(1<<j-1)][j-1]); 82 } 83 for (L=1;L<=n;L++) 84 { 85 for (i=1;i+L<=n;i+=L) 86 { 87 int p=lcp(i,i+L); 88 ans=max(ans,p/L+1); 89 if (i-L+p%L>=1) 90 { 91 ans=max(ans,lcp(i-L+p%L,i+p%L)/L+1); 92 } 93 } 94 } 95 printf("%d\n",ans); 96 }