题意:给出若干个模式串n<=5e2长度<=2e2和主串个m<=1e3长度<=1e4 问每个主串中包含哪几个模式串,输出编号.
建立字典时 把单词结尾设为编号,设p[i]为模式串是在某个母串中出现,对每个母串跑AC自动机即可
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N=201*500;
int flag;
struct Aho{
int chd[N][128],v[N],f[N],last[N],sz,ans;
int p[N];//p[i] 模式串i是否出现
void init()
{
memset(p,0,sizeof(p));
sz=1;ans=0;
memset(v,0,sizeof(v));
memset(f,0,sizeof(f));
memset(chd[0],0,sizeof(chd[0]));
}
void insert(char *s,int x)
{
int u=0,i=0;
while(s[i])
{
int id=s[i]-' ';
if(!chd[u][id])
{
memset(chd[sz],0,sizeof(chd[sz]));
chd[u][id]=sz++;
}
u=chd[u][id];
i++;
}
v[u]=x;//记录编号
}
void getFail()
{
queue<int> q;
f[0]=0;
for(int c=0;c<128;c++)
{
int u=chd[0][c];
if(u)
{
f[u]=0; q.push(u);last[u]=0;
}
}
while(!q.empty())
{
int r=q.front();q.pop();
for(int c=0;c<128;c++)
{
int u=chd[r][c];
if(!u)
{
chd[r][c]=chd[f[r]][c];
continue;
//补边
}
q.push(u);
int x=f[r];
//找到前缀i和后缀c相等
while(x&&!chd[x][c])
x=f[x];
f[u]=chd[x][c];
//last作用:若到i匹配成功,将母串中以后缀i结尾的单词进行快速匹配
//当母串中以后缀i的和某个模式串S匹配成功,则该模式串沿着失配边,找到前缀为模式串T,T和后缀s相同,同样也和母串后缀i相同
last[u]=v[f[u]]? f[u]:last[f[u]];
}
}
}
void solve(int j,int x)
{
if(!j) return;
if(v[j])
{
flag++;
p[v[j]]=1;//
}
solve(last[j],x);
}
void find(char *s,int x)
{
int n=strlen(s),j=0;
for(int i=0;i<n;i++)
{
int id=s[i]-' ';
j=chd[j][id];//trie
if(v[j])
solve(j,x);//匹配成功 看还有没有其他串和后缀i匹配
else if(last[j])
solve(last[j],x);//
}
}
}aho;
char s[10001];
int main()
{
int n,m;
while(cin>>n)
{
aho.init();
char dic[600];
int tot=0;
for(int i=1;i<=n;i++)
{
scanf("%s",dic);
aho.insert(dic,i);
}
aho.getFail();
cin>>m;
for(int i=1;i<=m;i++)
{
memset(aho.p,0,sizeof(aho.p));
flag=0;
int t=0;
scanf("%s",s);
aho.find(s,i);
if(flag)
{
printf("web %d:",i);
for(int k=1;k<=n;k++)
{
if(aho.p[k])
{
t++;
printf(" %d",k);
if(t>=flag)
break;
}
}
tot++;
printf("\n");
}
}
printf("total: %d\n",tot);
}
return 0;
}