题意:
给出若干个病毒串,不超过500个,每个病毒串长度在20~200之间。现在有若干个网站的原代码,要检测其中是否包含病毒,网站的个数不超过1000个,每个网站的原代码长度在7000-10000之间。已经如果包含病毒,最多包含3个病毒。输出每个含病毒网站包含的病毒的编号等信息,最后输出含病毒网站的个数。
AC自动机水题
AC代码:
#include<bits/stdc++.h>
using namespace std;
#define rint register int
struct AC{
int nxt[210*500][128],fail[210*500],id[210*500];
int vis[210*500],ans[550];
int sz;
void Init(){
for(rint i=0;i<=sz;i++){
fail[i] = id[i] = 0;
for(rint j=0;j<128;j++)
nxt[i][j] = 0;
}
sz = 0;
}
void Insert(char *s,int k){
int root = 0,len = strlen(s);
for(rint i=0;i<len;i++){
if(!nxt[root][s[i]]) nxt[root][s[i]] = ++sz;
root = nxt[root][s[i]];
}
id[root] = k;
}
void Build(){
queue<int> q;
for(rint i=0;i<128;i++)
if(nxt[0][i])
q.push(nxt[0][i]);
while(!q.empty()){
int u = q.front();
q.pop();
for(rint i=0;i<128;i++){
if(nxt[u][i]){
fail[nxt[u][i]] = nxt[fail[u]][i];
q.push(nxt[u][i]);
}
else nxt[u][i] = nxt[fail[u]][i];
}
}
}
bool Query(char *s,int num){
int root = 0,len = strlen(s);
memset(vis,0,sizeof(vis));
int ok = 0,k = 0;
for(rint i=0;i<len;i++){
if(!nxt[root][s[i]]) continue;
root = nxt[root][s[i]];
int tmp = root;
while(tmp && !vis[tmp]){
vis[tmp] = 1;
if(id[tmp]) ans[++k] = id[tmp],ok = 1;
tmp = fail[tmp];
}
}
if(!ok) return false;
printf("web %d:",num);
sort(ans+1,ans+k+1);
for(rint i=1;i<=k;i++) printf(" %d",ans[i]);
printf("\n");
return true;
}
}ac;
char S[10005],T[10005];
int main(){
int n,m;
while(~scanf("%d",&n)){
getchar();
ac.Init();
for(rint i=1;i<=n;i++){
gets(S);
ac.Insert(S,i);
}
ac.Build();
scanf("%d",&m);
getchar();
int res = 0;
for(rint i=1;i<=m;i++){
gets(T);
if(ac.Query(T,i))
res++;
}
printf("total: %d\n",res);
}
}