ZOJ3430-AC自动机

题意:先给你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;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值