1. 程式人生 > >hihocoder 1419 重復旋律4

hihocoder 1419 重復旋律4

oda void col 興趣 正確答案 des i++ targe body

描述

小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 }

hihocoder 1419 重復旋律4