【hihoCoder 1419】重复旋律4

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 }
原文地址:https://www.cnblogs.com/Yuzao/p/7157329.html