题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3065
题意:
给你n个串,再给你一个大长串,问你之前的n个串中出现过的串的次数。
解:
AC自动机解决,使用vis数组记录当前字符串出现的次数。每当匹配成功则+1,最后输出非0的vis就行。
关于AC自动机可看我的博客:AC自动机讲解+模板
代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <queue>
using namespace std;
const int maxn = 2e6+5;
const int N = 55;
char s[1005][N],s1[N],str[maxn];
int vis[1005];
struct Tries{
int nxt[1005*N][128],fail[1005*N],end[1005*N];
int root,L;
int newnode(){
for(int i = 0; i < 128 ; i++ )
nxt[L][i]=-1;
end[L++]=-1;
return L-1;
}
void init(){
L=0;
root = newnode();
}
void insert(char buf[],int id){
int len = strlen(buf);
int now = root;
for(int i = 0; i < len ; i++ )
{
if(nxt[now][buf[i]] == -1)
nxt[now][buf[i]] =newnode();
now = nxt[now][buf[i]];
}
end[now]=id ;
}
void build(){
queue<int>Q;
fail[root] = root;
for(int i = 0; i < 128; i++ )
if(nxt[root][i]==-1)
nxt[root][i] = root;
else
{
fail[nxt[root][i]] = root;/* *** */
Q.push(nxt[root][i]);
}
while(!Q.empty())
{
int now = Q.front();
Q.pop();
for(int i = 0;i < 128; i++ )
if(nxt[now][i]==-1)
nxt[now][i] = nxt[fail[now]][i]; /* *** */
else
{
fail[nxt[now][i]] = nxt[fail[now]][i];
Q.push(nxt[now][i]);
}
}
}
void query(char buf[])
{
memset(vis,0,sizeof(vis));
int len = strlen(buf);
int now = root;
//int res = 0;
for(int i = 0;i < len ; i++ )
{
now = nxt[now][buf[i]];
int tmp = now;
while( tmp != root)
{
if(end[tmp]!=-1)
vis[end[tmp]]++;
tmp = fail[tmp];
}
}
//return res;
}
};
Tries AC;
int main()
{
int n;
while(~scanf("%d",&n))
{
AC.init();
for(int i=1;i<=n;i++)
{
scanf("%s",s1);
strcpy(s[i],s1);
AC.insert(s[i],i);
}
AC.build();
scanf("%s",str);
AC.query(str);
for(int i=1;i<=n;i++)
{
if(vis[i]!=0)
{
printf("%s: %d\n",s[i],vis[i]);
}
}
}
return 0;
}