Description
小 Hi 平时的一大兴趣爱好就是演奏钢琴。 我们知道一个音乐旋律被表示为长度为 N的数构成的数列。
小 Hi 在练习过很多曲子以后发现很多作品中的旋律有重复的部分。
我们把一段旋律称为( k , l )-重复的, 如果它满足由一个长度为 l 的字符串重复了 k 次组成。 如旋律 abaabaabaaba 是(4,3)重复的, 因为它由 aba 重复 4 次组成。
小 Hi 想知道一部作品中 k 最大的(k,l)-重复旋律。
Input
一行一个仅包含小写字母的字符串 。 字符串长度不超过 100000。
Output
一行一个整数, 表示答案 k。
Sample Input
babbabaabaabaabab
Sample Output
4
Hint
数据约束:
30%的数据 N<=1000
70%的数据 N<=10000
100%的数据 N<=100000
题解:
容易想到判断循环结延伸的长度就是i和i+k(k为循环结长度)的lcp,求两个后缀的lcp显然就是高度数组对应的一段的最小值
RMQ维护即可
接着就是难点,我们不必枚举每一个位置,只需枚举k的倍数
但是可能存在情况:使得i+l i+l+1 (1<=l<=k)使得次数大了1
但是显然我们可以O1的找出这个位置的答案 即为 lcp(i-k+R%k,i+R%k) R为lcp(i,i+k) 可以画个图理解下
R%k是求出lcp不能形成新循环的多出来的一段 那么我们就直接求lcp即可
1 #include <algorithm> 2 #include <iostream> 3 #include <cstdlib> 4 #include <cstring> 5 #include <cstdio> 6 #include <cmath> 7 using namespace std; 8 const int N=100005; 9 int s[N],n=0,rk[N],sa[N],tmp[N],k;char S[N]; 10 bool comp(int i,int j){ 11 if(rk[i]!=rk[j])return rk[i]<rk[j]; 12 int ri=i+k<=n?rk[i+k]:-1; 13 int rj=j+k<=n?rk[j+k]:-1; 14 return ri<rj; 15 } 16 void Getsa(){ 17 for(int i=1;i<=n;i++){ 18 sa[i]=i;rk[i]=s[i]; 19 } 20 for(k=1;k<=n;k<<=1){ 21 sort(sa+1,sa+n+1,comp); 22 tmp[sa[0]]=0; 23 for(int i=1;i<=n;i++)tmp[sa[i]]=tmp[sa[i-1]]+comp(sa[i-1],sa[i]); 24 for(int i=1;i<=n;i++)rk[i]=tmp[i]; 25 } 26 } 27 int high[N]; 28 void Gethight(){ 29 int j,h=0; 30 for(int i=1;i<=n;i++){ 31 j=sa[rk[i]-1]; 32 if(h)h--; 33 for(;i+h<=n && j+h<=n;h++)if(s[i+h]!=s[j+h])break; 34 high[rk[i]-1]=h; 35 } 36 } 37 int f[N][25]; 38 int query(int l,int r){ 39 int k=log(r-l+1)/log(2); 40 return min(f[l][k],f[r-(1<<k)+1][k]); 41 } 42 void prework(){ 43 int to; 44 for(int i=1;i<=n;i++)f[i][0]=high[i]; 45 for(int j=1;j<=22;j++){ 46 for(int i=1;i<=n-(1<<j)+1;i++){ 47 to=i+(1<<(j-1)); 48 if(f[i][j-1]<f[to][j-1])f[i][j]=f[i][j-1]; 49 else f[i][j]=f[to][j-1]; 50 } 51 } 52 } 53 int lcp(int x,int y){ 54 if(rk[x]>rk[y])swap(x,y); 55 return query(rk[x],rk[y]-1); 56 } 57 int main() 58 { 59 //freopen("pp.in","r",stdin); 60 scanf("%s",S); 61 for(int i=0,sz=strlen(S);i<sz;i++) 62 s[++n]=S[i]-'a'+1; 63 Getsa(); 64 Gethight(); 65 prework(); 66 int ans=0,to; 67 for(int g=1;g<=n;g++){ 68 for(int i=1;i+g<=n;i+=g){ 69 to=lcp(i,i+g); 70 ans=max(ans,to/g+1); 71 if(i-g+(to%g)>=1){ 72 ans=max(lcp(i-g+to%g,i+to%g)/g+1,ans); 73 } 74 } 75 } 76 printf("%d ",ans); 77 return 0; 78 }