重复旋律3
时间限制:5000ms
单点时限:1000ms
内存限制:256MB
描述
小Hi平时的一大兴趣爱好就是演奏钢琴。我们知道一个音乐旋律被表示为长度为 N 的数构成的数列。小Hi在练习过很多曲子以后发现很多作品中的旋律有共同的部分。
旋律是一段连续的数列,如果同一段旋律在作品A和作品B中同时出现过,这段旋律就是A和B共同的部分,比如在abab 在 bababab 和 cabacababc 中都出现过。小Hi想知道两部作品的共同旋律最长是多少?
输入
共两行。一行一个仅包含小写字母的字符串。字符串长度不超过 100000。
输出
一行一个整数,表示答案。
- 样例输入
-
abcdefg abacabca
- 样例输出
-
3
#include<cstdio> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> using namespace std; const int maxn=210000; int Rank[maxn],cntA[maxn],cntB[maxn],A[maxn],B[maxn]; int sa[maxn],tsa[maxn],ht[maxn]; int ans,N,ch[maxn]; char str1[maxn],str2[maxn]; void solve() { int i,j; for(i=1;i<=N;i++) cntA[i]=0; for(i=1;i<=N;i++) cntA[ch[i]]++; for(i=1;i<=N;i++) cntA[i]+=cntA[i-1]; for(i=N;i>=1;i--) sa[cntA[ch[i]]--]=i; Rank[sa[1]]=1; for(i=2;i<=N;i++) { Rank[sa[i]]=Rank[sa[i-1]]; if(ch[sa[i]]!=ch[sa[i-1]]) Rank[sa[i]]++; } for(int L=1;Rank[sa[N]]<N;L<<=1) { for(i=0;i<=N;i++) cntA[i]=cntB[i]=0; for(i=1;i<=N;i++) cntA[A[i]=Rank[i]]++; for(i=1;i<=N;i++) cntB[B[i]=(i+L<=N)?Rank[i+L]:0]++; for(i=1;i<=N;i++) cntA[i]+=cntA[i-1]; for(i=1;i<=N;i++) cntB[i]+=cntB[i-1]; for(i=N;i>=1;i--) tsa[cntB[B[i]]--]=i; for(i=N;i>=1;i--) sa[cntA[A[tsa[i]]]--]=tsa[i]; Rank[sa[1]]=1; for(i=2;i<=N;i++) { Rank[sa[i]]=Rank[sa[i-1]]; if(A[sa[i]]!=A[sa[i-1]]||B[sa[i]]!=B[sa[i-1]]) Rank[sa[i]]++; } } for (i=1,j=0;i<=N;i++) { if(j) j --; while (ch[i+j]==ch[sa[Rank[i]-1]+j]) j++; ht[Rank[i]]=j; } } int main() { scanf("%s",str1+1); scanf("%s",str2+1); int L1=strlen(str1+1); int L2=strlen(str2+1); for(int i=1;i<=L1;i++) ch[i]=str1[i]-96; ch[L1+1]=30; for(int i=1;i<=L2;i++) ch[i+L1+1]=str2[i]-96; N=L1+L2+1; solve(); for(int i = 1; i <= N; i++) { if((sa[i]<=L1)!=(sa[i-1]<=L1)) ans = max(ans, ht[i]); } printf("%d ",ans); return 0; }
没有找到原因,开始用字符串一直错,改成数组就AC了。也不知道为什么。过几天再看看吧。