@lychee123
2017-07-12T19:04:27.000000Z
字数 1489
阅读 1426
数据结构
有t组测试数据,对于每组测试数据
给出N个单词(N <= 10000),每个单词都只包含小写字母(每个单词的长度不超过50)
接下来给你一个长串s(长度不超过1000000)
问上面的n个单词有多少个在长串s中出现过。
Sample Input
1
5
she
he
say
shr
her
yasherhsSample Output
3
AC自动机的模板题。但是有地方需要注意。
我们AC自动机的模板里面对于单词的标记是出现了就标记为1,这里由于可能出现相同的单词所以会重复去算。所以我们对于isword数组的存值为++。而不是==1.(在代码第21行)同时对于模板的find函数。66行到77行。我们应该标记已经出现的单词,ans加了之后就应该改变isword的值为0,不重复计数。
#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<queue>
using namespace std;
const int maxn=5e5+5;
int last[maxn],f[maxn];
int ch[maxn][26];
int cnt=0;
int isword[maxn];
void insert(char s[])
{
int root=0;
int l=strlen(s);
for(int i=0;i<l;i++)
{
if(ch[root][s[i]-'a']==0)
ch[root][s[i]-'a']=++cnt;
root=ch[root][s[i]-'a'];
}
isword[root]++;
}
void getfail()
{
queue<int>q;
f[0]=0;
for(int i=0;i<26;i++)
{
int u=ch[0][i];
if(u!=0)
{
f[u]=0;
q.push(u);
last[u]=0;
}
}
while(!q.empty())
{
int r=q.front();
q.pop();
for(int c=0;c<26;c++)
{
int u=ch[r][c];
if(u==0)
{
ch[r][c]=ch[f[r]][c];
continue;
}
q.push(u);
int v=f[r];
while(v&&!ch[v][c])
v=f[v];
f[u]=ch[v][c];
last[u]=isword[f[u]]?f[u]:last[f[u]];
}
}
}
int find(char T[])
{
int ans=0;
int n=strlen(T);
int j=0;
for(int i=0;i<n;i++)
{
j=ch[j][T[i]-'a'];
if(isword[j])
{
ans+=isword[j];
isword[j]=0;
}
int temp=last[j];
while(temp)
{
ans+=isword[temp];
isword[temp]=0;
temp=last[temp];
}
}
return ans;
}
char s[maxn*2];
char s1[10010];
int main()
{
int t;
scanf("%d",&t);
while(t--)
{
memset(ch,0,sizeof(ch));
memset(isword,0,sizeof(isword));
int n;
scanf("%d",&n);
while(n--)
{
scanf("%s",s1);
insert(s1);
}
getfail();
scanf("%s",s);
printf("%d\n",find(s));
}
return 0;
}