D - 娜娜梦游仙境系列——村民的怪癖
Problem Description
娜娜费劲九牛二虎之力终于把糖果吃完了(说好的吃不完呢?骗人,口亨~),于是,缘溪行,忘路之远近。忽逢桃花林,夹岸数百步,中无杂树,芳草鲜美,落英缤纷,娜娜甚异之。复前行,欲穷其林。林尽水源,便得一山,山有小口,仿佛若有光。便舍船,从口入。初极狭,才通人。复行数十步,豁然开朗。土地平旷,屋舍俨然,有良田美池桑竹之属。阡陌交通,鸡犬相闻。其中往来种作,男女衣着,悉如外人。黄发垂髫,并怡然自乐。(摘自《桃花源记》)
娜娜与村民交流了好久才发现这里的人们给孩子的命名方式很奇怪,首先村民们的名字都是用专门的符号来记录,正好是26个符号,于是娜娜就把它们替换成‘a’~‘z’,然后首先把爸爸的名字作为孩子的姓,妈妈的名字作为孩子的名。这时候肯定有人会问,不是独生子女怎么办?很简单~取拼接好的名字的前缀与后缀相同的部分从短到长依次作为孩子的姓名,啥,不够?那就不许你再生孩子!
不过由于桃花村民与世隔绝太久了,以致于他们总是无法正确判断一对夫妻最多能生多少个孩子,于是就把这个任务交给你了。
P.S. 若用S[1,n]表示一个长度为n的字符串,那么S[1,i](1<=i<=n)表示S的一个前缀,S[j,n](1<=j<=n)表示S的一个后缀。具体看样例解释
Input
多组数据,首先是一个正整数t(t<=20),表示数据的组数
对于每一组数据,包含两个只由'a'~'z'组成的不含空格的字符串S1,S2,分别代表丈夫的姓名以及妻子的姓名。(1<=|S1|,|S2|<=100000)
Output
Sample Input
2 ababc ababa aaaaa aaa
Sample Output
3 8
Hint
对于样例1,把丈夫和妻子的姓名拼接在一起是ababcababa,可以作为孩子的姓名的是a、aba、ababcababa,故最多生育3个孩子
对于样例2,把丈夫和妻子的姓名拼接在一起是aaaaaaaa,可以作为孩子的姓名的是a、aa、aaa、aaaa、aaaaa、aaaaaa、aaaaaaa、aaaaaaaa,故最多生育8个孩子
题意:把两个字符串拼接在一起,然后判断有多少前缀和后缀相同。
解法:我们和kmp算法的next数组的意义联系在一起,next[i]本质上的意义就是S[0...next[i]]==S[i-next[i],i]的最大长度。即最大的前缀与后缀相等长度。所以只要把拼接好的字符串求一次next值,看一下最后一个next值需要多少次跳到字符串头就是答案。
note:按我的理解是,next数组[i]就是当前位置(包括当前位置)的前next[i]个字符构成的子串等于该字符串的前缀,而next[i]的位置就是前缀的最后一个位置,因为前缀和当前位置子串相同,所以从next[i]再找与其相同的前缀,当前位置也存在相同的前缀。从最后一个next[len]开始向前推,就是找后缀有几个和前缀相同。
斟酌了半天写的,也不知道对不对,望指正。
Sample:
a b a b a b a
-1 0 0 1 2 3 4 5
( a b[ a b a ) b a ] 5 next[7]=5 : ( a b a b a ) = [ a b a b a ]
( a b< a ) b [ a>b a ] 3 next[5]=3 : ( a b a ) = < a b a > = [ a b a ]
( a ) b { a } b< a>b [ a ] 1 next[3]=1 : ( a ) = { a } = < a > = [ a ]
前缀等于后缀的有3种 : [ a b a b a ] ; [ a b a ] ; [ a ]
1 #include <stdio.h> 2 #include <string.h> 3 4 char a[200010],b[100005]; 5 int next[1000006]; 6 7 void getnext(char str[],int len) 8 { 9 int i=0,j=-1,m; 10 next[0]=-1; 11 m=len; 12 while(i<m) 13 { 14 if(j==-1||str[i]==str[j]) 15 { 16 i++; 17 j++; 18 next[i]=j; 19 } 20 else j=next[j]; 21 } 22 } 23 24 int main() 25 { 26 int t,i,sum,len; 27 while(scanf("%d",&t)==1) 28 { 29 while(t--) 30 { 31 scanf("%s %s",a,b); 32 strcat(a,b); 33 len=strlen(a); 34 getnext(a,len); 35 sum=1; 36 i=next[len]; 37 while(i!=0) 38 { 39 i=next[i]; 40 sum++; 41 } 42 printf("%d ",sum); 43 } 44 } 45 return 0; 46 }