题目描述
法语作家 Georges Perec (1936–1982) 曾经写过一本没有字母‘e’的书 La disparition,他是 Oulipo 组织的一个成员。从他的书中摘录如下: Tout avait Pair normal, mais tout s’affirmait faux. Tout avait Fair normal, d’abord, puis surgissait l’inhumain, l’affolant. Il aurait voulu savoir où s’articulait l’association qui l’unissait au roman : stir son tapis, assaillant à tout instant son imagination, l’intuition d’un tabou, la vision d’un mal obscur, d’un quoi vacant, d’un non-dit : la vision, l’avision d’un oubli commandant tout, où s’abolissait la raison : tout avait l’air normal mais…
Perec 可能会在这样的比赛中取得高分(或更确切地说,低分)。比赛要求人们写一段有关某个主题的有意义的文字,某个给定的词要尽可能少地出现。我们的工作是给出一个评判程序,统计出现的次数,以给出参赛者的排名。这些参赛者通常写很长的、废话连篇的文本;一个带 500,000 连续的‘T’的序列是常见的;而且他们从来不使用空格。 因此,给出一个字符串,我们要很快地发现这个字符串在一段文本中出现的次数。更规范地讲:给出字母表 {‘A’, ‘B’, ‘C’, …, ‘Z’},以及字母表上的两个有限的字符串:一个单词 W 和一段文本 T,计算 W 在 T 中出现的次数。所有 W 的连续字符必须严格地匹配 T 的连续字符。在文本 T 中,单词 W 的出现可能会重叠在一起。
输入输出格式
输入格式 输入文件的第一行给出一个整数,是后面给出的测试用例的个数。每个测试用例的格式如下:
- 一行给出单词 W,一个在字母表 {‘A’, ‘B’, ‘C’, …, ‘Z’} 上的字符串,
1≤∣W∣≤10,000
(|W| 表示字符串 W 的长度)。 - 一行给出文本 T,一个在字母表 {‘A’, ‘B’, ‘C’, …, ‘Z’} 上的字符串,|
W∣≤∣T∣≤1,000,000
。
输出格式 对于输入文件中的每个测试用例,在一行中输出一个数字:单词 W 在文本 T 中出现的次数。
输入输出样例1
输入
3
BAPC
BAPC
AZA
AZAZAZA
VERDI
AVERDXIVYERDIAN
输出
1
3
0
#include <cstdio> //预编译命令 #include <cstring> const int maxw = 10000 + 10; //单词w的长度上限 const int maxt = 1000000 + 10; //文本t的长度上限 int match(char w[], char s[], int next[]) { // 统计w[ ]在s[ ]中出现的次数 int cnt = 0; //w[ ]在s[ ]中的频率初始化 int slen = strlen(s); //计算s和w的串长 int wlen = strlen(w); int p = 0, cur = 0; //w和s的指针初始化 while (cur < slen) //若未扫描完s的所有字符 { if (s[cur] == w[p]) //若s和w的当前字符相同,则w和s的指针右移1个位置 { ++cur; ++p; } else if (p >= 0) //若未分析完w的所有字符,则根据next数组左移w的指针;否则s 的下一个字符与w的第1个字符匹配 { p = next[p]; } else { ++cur; p = 0; } if (p == wlen) // 若匹配成功,则w[ ]在s[ ]中的频率+1;根据next数组左移w[ ]的指针,从s[ ]的下一个字符开始继续匹配 { ++cnt; p = next[p]; } } return cnt; } int main(void) { int loop; scanf("%d", &loop); //输入测试用例数 while (loop--) { char w[maxw], t[maxt]; scanf("%s%s", w, t); //输入单词w和文本t int suffix[maxw]; //应用KMP算法计算单词w的前缀函数 suffix[0] = -1; suffix[1] = 0; int p = 0; for (int cur = 2; cur <= strlen(w); cur++) { while (p >= 0 && w[p] != w[cur - 1]) p = suffix[p]; suffix[cur] = ++p; } printf("%d\n", match(w, t, suffix)); //计算和输出单词w在文本t中的出现次数 } return 0; }