题目描述:
给出n个病毒特征码和m个源码,问每个源码中包含哪些病毒,将病毒按编号由小到大输出,保证最多包含三个病毒。
n<=500,病毒长度<=200,m<=1000,源码长度<=10000.
题目分析:
在AC自动机上存下每个节点对应的<=3个病毒即可。
Code:
#include<bits/stdc++.h>
using namespace std;
int n,m,num;
char s[10005];
struct AC_automaton{
#define maxn 100005
#define maxc 128
int ch[maxn][maxc],fail[maxn],tot,cnt[maxn],id[maxn][3];
void insert(char *s,int x){
int r=0,v;
for(int i=0;s[i];i++,r=ch[r][v])
if(!ch[r][v=s[i]]) ch[r][v]=++tot;
id[r][cnt[r]++]=x;
}
int q[maxn],L,R;
void build(){
q[L=R=0]=0;
while(L<=R){
int r=q[L++],c;
for(int i=0;i<maxc;i++)
if(c=ch[r][i]){
fail[c]=r?ch[fail[r]][i]:0,q[++R]=c;
for(int j=cnt[fail[c]]-1;j>=0&&cnt[c]<3;j--) id[c][cnt[c]++]=id[fail[c]][j];
}
else ch[r][i]=ch[fail[r]][i];
}
}
int ans[4];
void solve(char *s,int x){
int r=0; ans[0]=0;
for(int i=0;s[i];i++)
for(int j=cnt[r=ch[r][s[i]]]-1;j>=0;j--) ans[++ans[0]]=id[r][j];
if(ans[0]){
num++,sort(ans+1,ans+1+ans[0]),printf("web %d:",x);
for(int i=1;i<=ans[0];i++) if(i==1||ans[i]!=ans[i-1]) printf(" %d",ans[i]);putchar('\n');
}
}
}A;
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%s",s),A.insert(s,i);
A.build();
scanf("%d",&m);
for(int i=1;i<=m;i++) scanf("%s",s),A.solve(s,i);
printf("total: %d\n",num);
}