题意:多组数据,每组数据有n个字符串作为字典,然后给出另外一个字符串,询问这个新的字符串中有几个字典中的单词。
多个匹配串对单字符串匹配,AC自动机是标准解法,算是测试模板了【笑
然而RE了一发WA了一发…没看清数据范围
对于字典中的字符串建立trie树和fail指针,然后对待匹配串匹配即可
有一些奇怪的小细节譬如字典中可能有多个相同字符串,以及判重问题…恩还是很好解决的嘛
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int maxn = 500005;
const int maxm = 26;
int T, n, tot, ans, temp;
int ch[maxn][maxm], fail[maxn], flag[maxn], q[maxn], vis[maxn];
char s[maxn*2];
int cal(char c)
{
return c-'a';
}
void newnode(int x,int temp)
{
if(temp!=-1) ch[x][temp] = ++tot;
for(int i = 0; i < maxm; i++)
ch[tot][i]=0;
flag[tot]=0;
fail[tot]=0;
}
void addtrie(char s[])
{
int x = 0, p = 0;
int len = strlen(s);
while( p < len )
{
temp=cal(s[p]);
if( !ch[x][temp] ) newnode(x, temp);
x = ch[x][temp];
p++;
}
flag[x]++;
}
void getfail(void)
{
int h = 0, t = 0;
for(int i = 0; i < maxm; i++)
if( ch[0][i] ) q[t++] = ch[0][i];
while( h < t )
{
temp=q[h++];
for(int i = 0; i < maxm; i++)
if( !ch[temp][i] ) ch[temp][i] = ch[fail[temp]][i];
else
{
q[t++] = ch[temp][i];
fail[ch[temp][i]] = ch[fail[temp]][i];
}
}
}
int query(void)
{
int len = strlen(s), x = 0, p = 0;
temp = 0;
for(int i = 0; i < len; i++)
{
temp = s[i]-'a';
x = ch[x][temp];
p = x;
while( p && !vis[p] )
{
ans += flag[p];
flag[p] = 0;
vis[p] = 1;
p = fail[p];
}
}
return ans;
}
int main(void)
{
scanf("%d",&T);
while(T--)
{
tot = 0;
ans = 0;
newnode(0,-1);
memset(vis,0,sizeof(vis));
scanf("%d",&n);
for(int i = 0; i < n; i++)
{
scanf("%s",s);
addtrie(s);
}
getfail();
scanf("%s",s);
printf("%d\n",query());
}
return 0;
}