题意:先给出一个整数n,随后给出n个短字符串,再给出一个整数m,再给出m个长字符串,求出每个长字符串中都有哪几个段字符串。
AC自动机的裸题,可以在root节点上设置一个superroot作为root的fail指针来简化操作,这样对于root,就不用手动把每个子节点入队了·。
因为题目没有说只限于小写字母,所以每个节点应该有128个子节点。
#include <iostream>
#include <algorithm>
#include <string>
#include <stdio.h>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <iomanip>
#include <queue>
#define N 45000
using namespace std;
typedef long long ll;
int n,m;
char s1[210],s2[10010];
struct Trier{
int next[210*500][128],fail[210*500],end[210*500];
int root,L,super;
int newNode(){
L++;
for(int i=0;i<128;i++){
next[L][i] = -1;
}
end[L] = -1;
return L;
}
void init(){
L = -1;
super = newNode();
root = newNode();
for(int i=0;i<128;i++){
next[super][i] = root;
}
fail[root] = super;
}
void insert(char s[],int i){
int t = root;
for(;*s;s++){
if(next[t][*s] == -1){
next[t][*s] = newNode();
}
t = next[t][*s];
}
end[t] = i;
}
void build(){
int t = root;
queue<int>que;
que.push(root);
while (!que.empty())
{
t = que.front();que.pop();
for(int i=0;i<128;i++){
if(next[t][i] != -1){
fail[next[t][i]] = next[fail[t]][i];
que.push(next[t][i]);
}else{
next[t][i] = next[fail[t]][i];
}
}
}
}
bool used[510];
bool query(char s[]){
bool ans = 0;
memset(used,0,sizeof(used));
int t = root;
for(;*s;s++){
t = next[t][*s];
for(int u = t;u != root;u = fail[u]){
if(end[u] != -1){
used[end[u]] = 1;
ans = 1;
}
}
}
return ans;
}
};
Trier aa;
int main(){
int i,j,x,y;
aa.init();
scanf("%d",&n);
for(i=1;i<=n;i++){
scanf("%s",s1);
aa.insert(s1,i);
}
aa.build();
scanf("%d",&m);
int total = 0;
for(i=1;i<=m;i++){
scanf("%s",s2);
if(aa.query(s2)){
total++;
printf("web %d:",i);
for(j=0;j<=n;j++){
if(aa.used[j]){
printf(" %d",j);
}
}
printf("\n");
}
}
printf("total: %d\n",total);
return 0;
}