#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<set>
using namespace std;
struct ACautomata{
int next[100010][127],idx[100010],fail[100010],last[100010],num,root;
int newnode()
{
memset(next[num],0,sizeof next[num]);
idx[num]=0;
return num++;
}
void init()
{
num=0;
root=newnode();
}
void insert(char *s,int t)
{
int len=strlen(s),cur=root;
for(int i=0;i<len;++i)
{
int &tmp=next[cur][s[i]];
if(!tmp)tmp=newnode();
cur=tmp;
}
idx[cur]=t;
}
void getfail()
{
queue<int>q;
fail[root]=root;
for(int i=0;i<127;++i)
{
int u=next[root][i];
if(u)
{
fail[u]=last[u]=0;
q.push(u);
}
}
while(!q.empty())
{
int cur=q.front();
q.pop();
for(int i=0;i<127;++i)
{
int u=next[cur][i];
if(u)
{
fail[u]=next[fail[cur]][i];
last[u]=idx[fail[u]]?fail[u]:last[fail[u]];
q.push(u);
}
else next[cur][i]=next[fail[cur]][i];
}
}
}
bool query(char *s,int t)
{
set<int>ret;
int len=strlen(s),cur=root;
for(int i=0;i<len;++i)
{
cur=next[cur][s[i]];
int tmp=cur;
while(tmp!=root)
{
if(idx[tmp])ret.insert(idx[tmp]);
tmp=last[tmp];
}
}
if(ret.size())
{
printf("web %d:",t);
set<int>::iterator iter;
for(iter=ret.begin();iter!=ret.end();iter++)
printf(" %d",*iter);
puts("");
return 1;
}
else return 0;
}
}ac;
int n,ans;
char s[10010];
int main()
{
ac.init();
scanf("%d",&n);
for(int i=1;i<=n;++i)
{
scanf("%s",s);
ac.insert(s,i);
}
ac.getfail();
scanf("%d",&n);
for(int i=1;i<=n;++i)
{
scanf("%s",s);
ans+=ac.query(s,i);
}
printf("total: %d\n",ans);
}
思路就是来一个网站就匹配一次。。匹配到一个千万不要break。
记得保存病毒下标,用set方便输出答案。
我这题WA了几次,比如说tmp=last[tmp];
打成了tmp=fail[tmp]
还有就是charset变成了127而不是26,还要注意格式。