问题描述
有一个有趣的定理:无限猴子定理(infinite monkey theorem),它的表述如下:让一只猴子在打字机上随机按键,当按键次数达到无穷时,几乎必然能够打出任何给定的文字。
给出一篇猴子打出的“文章”,并给定一个由若干个词组成的词典,问猴子一共打出了多少个在词典中出现的词。
输入格式
第一行一个整数 n(1≤n≤10000),表示词典中单词的个数。
接下来 n 行,每行一个仅由小写字母组成的单词,长度不超过 50。
最后一行是一篇仅由小写字母组成的文章,长度不超过 1000000。
输出格式
一行一个整数,表示答案。
样例输入
5
jsk
jisuan
suantou
love
program
jisuantouisprogramming
样例输出
3
AC代码
#include<iostream>
#include<cstring>
#include<cstdio>
#define maxn 1000005
#define maxm 1000005
using namespace std;
int n,tot,head,tail,son[maxm][26],fai[maxm],sum[maxm],list[maxm];
char s[maxn];
void clear(){
tot=0;
memset(son,0,sizeof(son));
memset(sum,0,sizeof(sum));
}
void insert(char *s){
int p=0;
for (int i=1;s[i];p=son[p][s[i]-'a'],i++) if (!son[p][s[i]-'a']) son[p][s[i]-'a']=++tot;
sum[p]++;
}
void failed(){
head=0,tail=1,list[1]=0,fai[0]=-1;
while (head!=tail){
int x=list[++head];
for (int ch=0;ch<26;ch++)
if (son[x][ch]){
list[++tail]=son[x][ch];
int p=fai[x];
while (p!=-1&&!son[p][ch]) p=fai[p];
if (p==-1) fai[son[x][ch]]=0;
else fai[son[x][ch]]=son[p][ch];
}
}
}
void work(char *s){
int ans=0;
for (int i=1,p=0;s[i];i++){
while (p&&!son[p][s[i]-'a']) p=fai[p];
p=son[p][s[i]-'a'];
for (int t=p;t;t=fai[t]) ans+=sum[t],sum[t]=0;
}
printf("%d\n",ans);
}
int main()
{
cin>>n;
for (int i=1;i<=n;i++) scanf("%s",s+1),insert(s);
failed();
scanf("%s",s+1),work(s);
return 0;
}