AC自动机+base64解码 zoj3430 Detect the Virus

传送门:点击打开链接

题意:告诉你邮件内容,告诉你病毒,问内容里有多少种类的病毒。一听就知道是裸AC自动机,,但是有两个很恶心的地方。。首先是base64解码,还是第一次手撸这个也是麻烦..另外一个很容易弄错的地方就是,有的语言字节是从0~255,其实C语言的字节是从0~127是正数,最高位表示的是负数了...所以说,base64解码后,可能有的字节是大于127的,所以我们不能用char类型来存解码后的,而应该用unsigned char来存!刚开始我也没注意,一直是TLE,诶,。

#include<map>
#include<set>
#include<cmath>
#include<ctime>
#include<stack>
#include<queue>
#include<cstdio>
#include<cctype>
#include<string>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<functional>
#define fuck(x) cout<<"["<<x<<"]"
#define FIN freopen("input.txt","r",stdin)
#define FOUT freopen("output.txt","w+",stdout)
using namespace std;
typedef long long LL;

/*MX为总长度*/
const int MN = 600 + 5;
const int MX = 33000 + 5;
const int P = 256;

struct AC_machine {
    int rear, root, vis[MN];
    short Next[MX][P], Fail[MX], End[MX];

    void Init() {
        rear = 0;
        root = New();
    }

    int New() {
        rear++;
        End[rear] = 0;
        for(int i = 0; i < P; i++) {
            Next[rear][i] = -1;
        }
        return rear;
    }

    void Add(unsigned char *A, int n, int u) {
        int now = root;
        for(int i = 0; i < n; i++) {
            int id = A[i];
            if(Next[now][id] == -1) {
                Next[now][id] = New();
            }
            now = Next[now][id];
        }
        End[now] = u;
    }

    void Build() {
        queue<int>Q;
        Fail[root] = root;
        for(int i = 0; i < P; i++) {
            if(Next[root][i] == -1) {
                Next[root][i] = root;
            } else {
                Fail[Next[root][i]] = root;
                Q.push(Next[root][i]);
            }
        }

        while(!Q.empty()) {
            int u = Q.front();
            Q.pop();

            for(int i = 0; i < P; i++) {
                if(Next[u][i] == -1) {
                    Next[u][i] = Next[Fail[u]][i];
                } else {
                    Fail[Next[u][i]] = Next[Fail[u]][i];
                    Q.push(Next[u][i]);
                }
            }
        }
    }

    int Query(unsigned char *S, int n) {
        memset(vis, 0, sizeof(vis));
        int now = root, ret = 0;
        for(int i = 0; i < n; i++) {
            now = Next[now][S[i]];
            int temp = now;

            while(temp != root) {
                if(End[temp] && !vis[End[temp]]) {
                    vis[End[temp]] = 1;
                    ret++;
                }
                temp = Fail[temp];
            }
        }
        return ret;
    }
} AC;
inline int ID(char x) {
    if('A' <= x && x <= 'Z') return x - 'A';
    if('a' <= x && x <= 'z') return 26 + x - 'a';
    if('0' <= x && x <= '9') return 52 + x - '0';
    if(x == '+') return 62;
    if(x == '/') return 63;
    return 0;
}

int base64_decode(char *A, unsigned char *B) {
    int n = strlen(A), r = 0;
    for(int t = 0; t < n / 4 - 1; t++) {
        int ret = 0;
        for(int j = t * 4; j < (t + 1) * 4; j++) {
            ret = ret << 6 | ID(A[j]);
        }
        B[r++] = ret >> 16 & 255;
        B[r++] = ret >> 8 & 255;
        B[r++] = ret & 255;
    }

    int ret = 0;
    for(int j = n - 4; j <= n - 1; j++) {
        if(A[j] != '=') ret = ret << 6 | ID(A[j]);
    }
    if(A[n - 2] == '=' && A[n - 1] == '=') {
        B[r++] = ret >> 4 & 255;
    } else if(A[n - 1] == '=') {
        B[r++] = ret >> 10 & 255;
        B[r++] = ret >> 2 & 255;
    } else {
        B[r++] = ret >> 16 & 255;
        B[r++] = ret >> 8 & 255;
        B[r++] = ret & 255;
    }
    B[r] = 0;
    return r;
}

char word[MX];
unsigned char after[MX];

int main() {
    int n, m; //FIN;
    while(~scanf("%d", &n)) {
        AC.Init();
        for(int i = 1; i <= n; i++) {
            scanf("%s", word);
            int len = base64_decode(word, after);
            AC.Add(after, len, i);
        }
        AC.Build();

        scanf("%d", &m);
        for(int i = 1; i <= m; i++) {
            scanf("%s", word);
            int len = base64_decode(word, after);
            printf("%d\n", AC.Query(after, len));
        }
        printf("\n");
    }
    return 0;
}


你可能感兴趣的:(AC自动机+base64解码 zoj3430 Detect the Virus)