病毒侵袭
题目大意:给定一些字符串和一些文本,找出每个文本中出现的所有字符串。
解题思路:AC自动机问题,注意字典树插入字符串的时候开一个 vis 数组记录一下结尾节点以及是哪个串,然后匹配即可。
因为是可见acsll码,字符要开到128,我扫了一眼题就开始做了,没看到这句话,一直按英文字母做的,结果wa 了8发
Code:
#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
#include <map>
#define inf 0x3f3f3f3f
#define ll long long
#define INT 9654234
using namespace std;
const int maxn = 100005;
vector<int> ans;
struct Trie{
int next[maxn][128],fail[maxn],end[maxn],size[maxn]; //可见acsll码128 不是26
int root,l;
int newnode(){
for(int i=0;i<128;i++) next[l][i]=-1;
end[l++]=0;
return l-1;
}
void init(){
l=0;
memset(size,0,sizeof size);
root =newnode();
}
void insert(char buf[],int x){
int len=strlen(buf);
int now=root;
for(int i=0;i<len;i++){
if(next[now][buf[i]]==-1)
next[now][buf[i]]=newnode();
now=next[now][buf[i]];
}
size[now]=x; //记录第几个串
}
void bulid(){
queue<int> q;
fail[root]=root;
for(int i=0;i<128;i++){
if(next[root][i]==-1) next[root][i]=root;
else {
fail[next[root][i]]=root;
q.push(next[root][i]);
}
}
while(!q.empty()){
int now= q.front();
q.pop();
for(int i=0;i<128;i++){
if(next[now][i]==-1) next[now][i]=next[fail[now]][i];
else{
fail[next[now][i]]=next[fail[now]][i];
q.push(next[now][i]);
}
}
}
}
int query(char buf[]){
int len=strlen(buf);
int now=root;
int res=0,flag=0;
for(int i=0;i<len;i++){
///
now=next[now][buf[i]];
for(int tmp=now;tmp;tmp=fail[tmp]){
if(size[tmp]){
ans.push_back(size[tmp]);
flag=1;
}
if(ans.size()>=3) break; //因为题目说最多三个病毒,直接break剪枝
}
}
return flag;
}
} ac;
char buf[10022];
int main()
{
ios::sync_with_stdio(0);
cin.tie(0);cout.tie(0);
int T,n,m;
while(scanf("%d",&n)==1&&n){
int all=0;
ac.init();
for(int i=1;i<=n;i++){
scanf("%s",&buf);
ac.insert(buf,i);
}
ac.bulid();
scanf("%d",&m);
for(int i=1;i<=m;i++){
ans.clear();
scanf("%s",&buf);
if(ac.query(buf)){
all++;
sort(ans.begin(),ans.end());
printf("web %d:",i);
for(int i=0;i<ans.size();i++){
printf(" %d",ans[i]);
}
printf("\n");
}
}
printf("total: %d\n",all);
}
return 0;
}