题目大意:
法国的一位作家乔治·佩雷克曾写过一本书《失踪者》,整本书里没有一个含字母e的单词,他也是Oulipo组织的成员。
佩雷克经常参加一种比赛并得高分,比赛内容是写一篇有指定主题的文章,文章里不能含给定的单词,而我们需要提供一种裁判程序,判定选手在文章中出现过指定单词多少次并记分。
现有多个测例(测例数题中给出),每个测例中都给出指定一个单词W(不含空格,长度为[1, 10000])和一篇文章(长度为[|W|, 1000000]),这些字符串都是建立在大写字母表上的,对于每个测例都输出单词在文章中出现的次数。
注释代码:
/*
* Problem ID : POJ 3461 Oulipo
* Author : Lirx.t.Una
* Language : G++
* Run Time : 94 ms
* Run Memory : 1404 KB
*/
#pragma G++ optimize("O2")
#include <string.h>
#include <stdio.h>
//maximum word length
//单词的最大长度
//由于是从下标1开始存放的因此需要+2
#define MAXWDLEN 10002
//maximum text length
//文章的最大长度
//同理+2
#define MAXTXTLEN 1000002
char w[MAXWDLEN];//word,存放单词
//next数组
//next[i]表示字符串w[1-i]的一个最长前缀
//这个最长前缀等于该字符串的一个后缀
//比如字符串1235123中w[7]=3(即最后一个字符)
//而next[7]=3,w[3]=3
//这里next[7]得到的是一个下标3,通过该下表得到字符3
//注意,以下标3为结尾的字符串123就是w[7]的最长前缀
//前缀123和后缀123完全相等
int nxt[MAXWDLEN];
char t[MAXTXTLEN];//text,存放文章
void
bd_nxt(int len) {//build next
//构造next数组
//其构造方法和kmp算法相同
//只是主串和模式串都是w自己而已
//len为w的长度
int i, j;//i为主串指针,j为模式串的匹配指针
//算法运作是i不断向前
//j根据是否能和i指向的字符匹配而利用next数组回退
nxt[1] = 0;//首字符无法回溯,只能回退会0
//由于next数组还未构造,因此只能从头开始构造
//后面的利用前面的
//是一种动态规划的思想
for ( j = 0, i = 2; i <= len; i++ ) {//j初始化为0,表示还未进行匹配
//i由于1已经初始化过了,因此从2开始算起
while ( j > 0 && w[j + 1] != w[i] )//如果j不指向空且j + 1不能能和i匹配
j = nxt[j];//就回退
if ( w[j + 1] == w[i] )//当j为空或者j + 1能匹配上了则j跟随i请进
j++;
nxt[i] = j;//赋值
}
}
int
kmp( int wlen, int tlen ) {//KMP算法
//两个参数分别为w长度和t的长度
int i, j;//主、模指针
int cnt;//count,记录w在t中出现的次数
bd_nxt(wlen);//先构造next数组
for ( cnt = 0, j = 0, i = 1; i <= tlen; i++ ) {
while ( j > 0 && w[j + 1] != t[i] )
j = nxt[j];
if ( w[j + 1] == t[i] )
j++;
if ( j == wlen ) {//注意:当w完全匹配上了以后
cnt++;//不仅计数++
j = nxt[j];//并且j需要回退,因为w可能存在前缀和后缀重叠的两个部分
}
}
return cnt;
}
int
main() {
int nscn;
scanf("%d", &nscn);
while ( nscn-- ) {
scanf("%s%s", w + 1, t + 1);
printf("%d\n", kmp( strlen(w + 1), strlen(t + 1) ));
}
return 0;
}
无注释代码:
#pragma G++ optimize("O2")
#include <string.h>
#include <stdio.h>
#define MAXWDLEN 10002
#define MAXTXTLEN 1000002
char w[MAXWDLEN];
int nxt[MAXWDLEN];
char t[MAXTXTLEN];
void
bd_nxt(int len) {
int i, j;
nxt[1] = 0;
for ( j = 0, i = 2; i <= len; i++ ) {
while ( j > 0 && w[j + 1] != w[i] )
j = nxt[j];
if ( w[j + 1] == w[i] )
j++;
nxt[i] = j;
}
}
int
kmp( int wlen, int tlen ) {
int i, j;
int cnt;
bd_nxt(wlen);
for ( cnt = 0, j = 0, i = 1; i <= tlen; i++ ) {
while ( j > 0 && w[j + 1] != t[i] )
j = nxt[j];
if ( w[j + 1] == t[i] )
j++;
if ( j == wlen ) {
cnt++;
j = nxt[j];
}
}
return cnt;
}
int
main() {
int nscn;
scanf("%d", &nscn);
while ( nscn-- ) {
scanf("%s%s", w + 1, t + 1);
printf("%d\n", kmp( strlen(w + 1), strlen(t + 1) ));
}
return 0;
}
单词解释:
Oulipo:一个法国的作家以及数学家组织
Perec:人名,佩雷克(法国作家)
La disparition:佩雷克小说《失踪者》
or rather:更精确地说,倒不如说
subject:n, 主题
occurrence:n, 出现,发生
jury:n, 陪审团,评判委员会
ranking:n, 等级,地位,排名
competitor:n, 竞争者,对手
nonsense:n, 胡说,废话
formally:adv, 正式地,形式地
alphabet:n, 字母表
finite:adj, 有限的
overlap:vt/vi, 重叠