题目描述
给定n个模式串和1个文本串,求有多少个模式串在文本串里出现过。
输入格式
第一行一个n,表示模式串个数;
下面n行每行一个模式串;
下面一行一个文本串。
输出格式
一个数表示答案
输入输出样例
输入 #1
2
a
aa
aa
输出 #1
2
说明/提示
subtask1[50pts]:∑length(模式串)<=106,length(文本串)<=106,n=1; subtask1[50pts]:∑length(模式串)<=106,length(文本串)<=106,n=1;
运用结构:trie树和KMP;
思路:先建一颗trie树,然后用BFS搜索节点失败建立fail指针,
---------最后再遍历文本串统计
Σ
\Sigma
Σed[i]即可。
以下为代码:QWQ
#include<bits/stdc++.h>
#define N 1005000
using namespace std;
char s[N],t[N];
int tree[N][26];
int ed[N],fail[N],last[N];
int n,tot;
void Build(char *s)
{
int p=0,L=strlen(s);
for(int i=0;i<L;i++)
{
int c=s[i]-'a';
if(!tree[p][c])
{
memset(tree[tot],0,sizeof(tree[tot]));
ed[tot]=0;
tree[p][c]=tot++;
}
p=tree[p][c];
}
ed[p]++;
}
void Getfail()
{
queue<int>q;
fail[0]=0;
int p=0;
for(int i=0;i<26;i++)
{
p=tree[0][i];
if(p)
{
q.push(p);
fail[p]=0;
last[p]=0;
}
}
while(!q.empty())
{
int r=q.front();q.pop();
for(int i=0;i<26;i++)
{
p=tree[r][i];
if(!p)
{
tree[r][i]=tree[fail[r]][i];
continue;
}
q.push(p);
int v=fail[r];
while(v&&!tree[v][i])v=fail[v];
fail[p]=tree[v][i];
if(ed[fail[p]])last[p]=fail[p];
else last[p]=last[fail[p]];
}
}
}
int Search(char *s)
{
int p=0,cnt=0,L=strlen(s);
for(int i=0;i<L;i++)
{
int c=s[i]-'a';
p=tree[p][c];
int temp=0;
if(ed[p])temp=p;
else if(last[p])
temp=last[p];
while(temp)
{
cnt+=ed[temp];
ed[temp]=0;
temp=last[temp];
}
}
return cnt;
}
int main()
{
//memset(tree[0],0,sizeof(tree[0]));
//memset(ed,0,sizeof(ed));
tot=1;
scanf("%d",&n);
for(int i=1;i<=n;i++)
{
scanf("%s",t);
Build(t);
}
Getfail();
scanf("%s",s);
int ans=Search(s);
printf("%d\n",ans);
return 0;
}