给定 n
个长度不超过 50 的由小写英文字母组成的单词准备查询,以及一篇长为 m
的文章,问:文中出现了多少种待查询的单词。
Input
第一行一个整数 T
,表示数据组数;
对于每组数据,第一行一个整数 n
,接下去 n
行表示 n
个单词,最后一行输入一个字符串,表示文章。其中,1≤n≤10^4,1≤m≤10^6。
Output
对于每组数据,输出一个数,表示文中出现了多少个待查询的单词。
Sample Input
1
5
she
he
say
shr
her
yasherhs
Sample Output
3
字典树模板,注意一定要初始化!
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int maxn=1e6+5;
char t[maxn];
int trie[maxn][26];
int flag[maxn];
int fail[maxn];
int tot;
void init()
{
tot=0;
memset(trie,0,sizeof(trie));
memset(flag,0,sizeof(flag));
memset(fail,0,sizeof(fail));
}
void insert_(char *s) //建立字典树
{
int p=0;
for(int i=0; s[i]!='\0'; i++)
{
int c=s[i]-'a';
if(!trie[p][c])
trie[p][c]=++tot;
p=trie[p][c];
}
flag[p]++;
}
void getfail()
{
queue<int> q;
for(int i=0; i<26; i++)
{
if(trie[0][i])
{
fail[trie[0][i]]=0;
q.push(trie[0][i]);
}
}
while(!q.empty())
{
int k=q.front();
q.pop();
for(int i=0; i<26; i++)
{
if(trie[k][i])
{
fail[trie[k][i]]=trie[fail[k]][i];
//让失败结点指向父节点fail指针指向结点的下一节点
q.push(trie[k][i]);
}
else
trie[k][i]=trie[fail[k]][i];
}
}
}
int query(char *s)
{
int ans=0;
int p=0;
for(int i=0; s[i]!='\0'; i++)
{
int c=s[i]-'a';
p=trie[p][c];
int j=p;
for(int j=p; j&&flag[j]!=-1; j=fail[j])
{
ans+=flag[j];
flag[j]=-1;
}
}
return ans;
}
int main()
{
int T;
scanf("%d",&T);
while(T--)
{
init();
int n;
scanf("%d",&n);
char s[55];
tot=0;
for(int i=0; i<n; i++)
{
scanf("%s",s);
insert_(s);
}
getfail();
scanf("%s",t);
printf("%d\n",query(t));
}
return 0;
}