acdream 1683 村民的怪癖(KMP,经典变形)

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个孩子

题意:给两个串,合并他们成为1串。假设abcdefg是一个串,如果串头和串尾匹配,就可以是一个合法的名字,比如:7个的abcdefg和abcdefg,6个的abcdef和bcdefg,5个的abcde和cdefg.....直到1个的a和g。问有多少对匹配了?

思路:KMP的经典变形,这里仅有一个模式串而已,没原串。只需要对模式串求next数组就可以得到结果了,时间是O(n)。具体看下例:

假如有两串:ababc ababa

合并后变为:ababcababa

求next数组之后变为:

第1  2  3  4  5  6  7  8  9  10个

0  0  1  2  0  1  2  3  4  3
   a  b  a   b  c  a  b  a   b  a

找最长的合法串:第10个字符为a,而next[10]表示s[10-3+1,10]等同于s[1,3]这两个小串是相同的,也就是一个合法的名字,而且该名字是最长的(也就是长度9,因为10个的话就是自身了,毋庸置疑)。如下两个红色串:

ababcababa

接下来找次长的合法串:第next[10]个(即第3个,是a)的next应该是next[3],即1。也就是说s[1]=s[3]。而这个串在上一步才提到,是等于尾串的!看上面尾部红色的字符,aba=前部的aba,而前部aba中的后部a又等于前部的a。这说明了又是一个合法的名字。

ababcababa

接下来到next[1]=0了,也就没有再多可以匹配的了, 仅剩1个字符无法跟别人匹配。

这是模式串next数组本身的特点。细心点就可以发现。

 1 #include <bits/stdc++.h>
 2 #define LL long long
 3 using namespace std;
 4 const int N=1005;
 5
 6 void get_next(string &m, vector<int> &next) //求next数组
 7 {
 8     next.push_back(-1); //一开始是-1
 9     int i=0, j=-1;
10     while(i<m.size())
11     {
12         if(j==-1 || m[i]==m[j])      //j在原串上, i在模式串上
13         {
14             next.push_back(++j);
15             ++i;
16         }
17         else    j = next[j];
18     }
19 }
20
21 int cal(string &m)
22 {
23     vector<int> next;
24     get_next(m, next);
25     int len=m.size();
26     if(next[len]==len-1)  return len;  //全都一样的
27     int i=next[len], cnt=0;
28     while(i>0)      //只要next[i]>0就是一个匹配
29     {
30         cnt++;
31         i=next[i];//注意串s是以0开头的,而next是以1开头的。
32     }
33     return cnt+1;   //本身就是一个符合条件的串
34 }
35
36 int main()
37 {
38     freopen("e://input.txt", "r", stdin);
39     int t;
40     cin>>t;
41     string s1,s2;
42     while(t--)
43     {
44         cin>>s1>>s2;
45         s1+=s2;
46         printf("%d\n",cal(s1));
47     }
48     return 0;
49 }

AC代码

时间: 2024-10-11 17:38:57

acdream 1683 村民的怪癖(KMP,经典变形)的相关文章

ACdream HUT新生摸底训练赛 D - 娜娜梦游仙境系列——村民的怪癖 KMP

解题思路:用next数组进行跳转次数统计. 解题代码: 1 // File Name: d.cpp 2 // Author: darkdream 3 // Created Time: 2015年04月12日 星期日 19时40分52秒 4 5 #include<vector> 6 #include<list> 7 #include<map> 8 #include<set> 9 #include<deque> 10 #include<stac

D - 娜娜梦游仙境系列——村民的怪癖

D - 娜娜梦游仙境系列——村民的怪癖 Time Limit: 2000/1000MS (Java/Others)    Memory Limit: 128000/64000KB (Java/Others) Submit Status Problem Description 娜娜费劲九牛二虎之力终于把糖果吃完了(说好的吃不完呢?骗人,口亨~),于是,缘溪行,忘路之远近.忽逢桃花林,夹岸数百步,中无杂树,芳草鲜美,落英缤纷,娜娜甚异之.复前行,欲穷其林.林尽水源,便得一山,山有小口,仿佛若有光.便

acdream 1683(kmp)

题意:有两个夫妻,名字分别是a和b两个字符串,然后给孩子起名字,名字可以是父亲的名字前缀和母亲名字后缀相等的那部分,问可以给孩子起多少个名字. 题解:kmp中的next[i]数组记录了前i个字符前缀与后缀相等的长度是多少,那么可以利用这个特性,先把a和b拼接起来总长度是len,然后得到next数组,从next[len]往前找,前缀与后缀相等的串中是否还有前后缀相等串存在,一直到next[i] = 0,结果加1因为a和b拼接起来的本身串也符合条件. #include <stdio.h> #inc

KMP算法变形——对链表的处理

KMP算法简单粗暴的代码,严密的逻辑,初学的时候,真的很难搞懂,不过曾力胜老师这周出的模式串匹配的变形题目,让我反思了一下KMP算法,昨天晚上写出了链表形式,也算是进步吧.昨天太急,没来得及记录,今天补充起来. /* Name: KMP之链表写法 Date :2015/3/29 Write by:杨领 */ #include<stdio.h> #include<stdlib.h> typedef struct node { int data;//数据域 struct node *n

HDU 5918 SequenceI (2016 CCPC长春站 KMP模版变形)

这个题目的数据应该是比较弱的,赛场上的时候我们暴力也过了,而且我的kmp居然比暴力还要慢…… 这个变形并不难,跳着选数,把漏掉的位置补上就可以了. 代码如下: #include<iostream> #include<cstring> #include<cstdio> #include<cmath> #include<algorithm> using namespace std; #define N 1000005 int a[N],b[N],Ne

UVA 10537 The Toll! Revisited 过路费(最短路,经典变形)

题意:给一个无向图,要从起点s运送一批货物到达终点e,每个点代表城镇/乡村,经过城镇需要留下(num+19)/20的货物,而经过乡村只需要1货物即可.现在如果要让p货物到达e,那么从起点出发最少要准备多少货物?输出答案和路径(多条路径则必须输出字典序最小的).注:终点需要花费,而起点不需要. 思路:这最短路变形的不错.要逆推过来求最短路径,那么就从e出发到s的距离!只是p比较大,而且城镇还得推出前一站到底需要多少货物,既然直接计算那么麻烦,也可以一直p++直到能留下p为止就推出来了:而乡村就容易

HDU 1711 Number Sequence (数字KMP,变形)

题意:在一个序列中找到一个连续的子序列,返回其开始位置. 思路:每个数字当成1个字符,长的序列是原串,短的序列是模式串,求next数组后进行匹配. 1 #include <iostream> 2 #include <cmath> 3 #include <cstdio> 4 using namespace std; 5 const int N=1000010; 6 int a[N]; 7 int nextt[10010]; 8 int b[10010]; 9 int n,

KMP字符串匹配 fzu2275重现赛POJ3167

KMP原理  点击 FZU 2275 Game 乍一看是个博弈的题目,实际上是重现里面比较简单的字符匹配. 只要B是0,那么A一定赢.只要A的长度小于B,那么B一定赢. 只有当A中可以搜索到B,也就是B或者B的反转是A的子串,那么A就可以赢. #include <stdio.h> #include <stdlib.h> #include <string.h> #include <iostream> #include <math.h> #inclu

KMP,Trie,AC自动机题目集

字符串算法并不多,KMP,trie,AC自动机就是其中几个最经典的.字符串的题目灵活多变也有许多套路,需要多做题才能体会.这里收集了许多前辈的题目做个集合,方便自己回忆. KMP题目:https://blog.csdn.net/qq_38891827/article/details/80501506 Trie树题目:https://blog.csdn.net/qq_38891827/article/details/80532462 AC自动机:模板https://www.luogu.org/bl