hihocoder 1419 重复旋律4

描述

小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
",ans);
96 }
原文地址:https://www.cnblogs.com/Y-E-T-I/p/8514661.html