题意:先给你n个编码后病毒(字符串),然后在输入m个编码后的文件(字符串)要你求未编码钱文件里面含有几种病毒
题解思路:先反编码回去然后就是AC自动机模板顺便写个标记数组标记一下那些病毒已经被用过了
#include<iostream>
#include<cstring>
#include<queue>
#include<algorithm>
#include<cstdio>
using namespace std;
const int mx = 1e5+5;
const char *p = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
int mp[256];
bool used[50005];
struct trie{
int ch[50005][256];
int f[50005];
int v[50005];
int last[50005];
int sz;
void init(){
memset(ch[0],0,sizeof(ch[0]));
memset(f,0,sizeof(f));
memset(last,0,sizeof(last));
memset(v,0,sizeof(v));
sz = 1;
}
void insert(int *s){
int u = 0;
for(int i = 1; i <= s[0]; i++){
int d = s[i];
if(!ch[u][d]){
memset(ch[sz],0,sizeof(ch[sz]));
ch[u][d] = sz++;
}
u = ch[u][d];
}
v[u]++;
}
void getfail(){
queue<int>q;
for(int d = 0; d < 256; d++){
int ret = ch[0][d];
if(!ret){
ch[0][d] = 0;
continue;
}
f[ret] = last[ret] = 0;
q.push(ret);
}
while(!q.empty()){
int u = q.front();
q.pop();
for(int d = 0; d < 256; d++){
if(!ch[u][d]){
ch[u][d] = ch[f[u]][d];
continue;
}
int ret = ch[u][d];
f[ret] = ch[f[u]][d];
last[ret] = v[f[ret]]?f[ret]:last[f[ret]];
q.push(ret);
}
}
}
int find(int *s){
int u = 0;
int ans = 0;
for(int i = 1; i <= s[0]; i++){
int d = s[i];
int ret = ch[u][d];
while(ret){
if(!used[ret]){
ans+=v[ret];
used[ret] = 1;
}
ret = last[ret];
}
u = ch[u][d];
}
return ans;
}
}word;
char str[mx];
int s[mx];
void renode(char *a){
s[0]=0;
for(int i=0,len=0,x=0;a[i] && a[i] != '=';++i){
len+=6,x=(x<<6)|mp[a[i]];
if(len>=8){
s[++s[0]]=(x>>(len-8))&0xff;//保留前面的8位数
len-=8;
}
}
}
int main(){
int n;
for(int i = 0; i <= 63; i++)
mp[p[i]] = i;
while(scanf("%d",&n)!=EOF){
word.init();
for(int i = 0; i < n; i++){
scanf("%s",str);
renode(str);
//cout<<s[0]<<endl;
word.insert(s);
}
word.getfail();
int m;
scanf("%d",&m);
for(int i = 0; i < m; i++){
scanf("%s",str);
renode(str);
memset(used,0,sizeof(used));
printf("%d\n",word.find(s));
}
printf("\n");
}
return 0;
}