Detect the Virus - ZOJ 3430(恶心的自动机)
题目大意:给你一些病毒的特征码,然后再给一些文本,判断每个文本有多少种病毒,不过给的字符串都是加密处理过的,给的每个字符串都有对应一个64以内的一个数(题目里面那个表就是),然后可以把这个64以内的这个数化成6位的二进制数,然后把这些二进制数每8位再化成一个字符,这就是原来的字符,比如 QA== ->编号0 1->二进制010000 000000->每8位变成一个字符 01000000 0000(后面这4个0就是那两个==,可以舍去)-> 64('@')。
分析:因为是化成8位的二进制,2^8 = 256,不过因为有‘\0’这样的字符,所以无法使用char来搞,开一个int数组是个不错的选择,当然也得注意内存开销,申请内存的方式会MLE,实验得出结果开6W最好.....真是让人感觉很恶心,错了19次!!
代码如下:
===============================================================================================================================
#include<stdio.h> #include<string.h> #include<algorithm> #include<queue> using namespace std; const int MAXN = 10007; const int MAXM = 256;///2^8 const int oo = 1e9+37; const char cb64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; int virus[MAXN], MumStr[MAXN]; char s[MAXN]; int password[MAXN*8]; struct node { int Fail, next[MAXM]; int leaf, num; void InIt() { Fail = leaf = num = 0; memset(next, 0, sizeof(next)); } }trie[60000]; int top; int TurnStr(char s[], int p[]) { int i, j, k=0; for(i=0; s[i] && s[i] != '='; i++) { s[i] = strchr(cb64, s[i]) - cb64; for(j=5; j>=0; j--) { password[k+j] = s[i] % 2; s[i] /= 2; } k += 6; } int len = 0; for(i=j=0; i<k; i++) { j = j*2 + password[i]; if((i+1) % 8 == 0) { p[len++] = j; j = 0; } } return len; } void Insert(int root, int N) { int p = root; for(int i=0; i<N; i++) { int k = virus[i]; if(trie[p].next[k] == 0) { trie[p].next[k] = ++top; trie[top].InIt(); } p = trie[p].next[k]; } trie[p].leaf += 1; } void GetFail(int root) { int p = root, temp; queue<int> Q; trie[root].Fail = -1; for(int i=0; i<MAXM; i++)if(trie[p].next[i]) { int k = trie[p].next[i]; trie[k].Fail = root; Q.push(k); } while(Q.size()) { p = Q.front(); Q.pop(); for(int i=0; i<MAXM; i++)if(trie[p].next[i]) { int k = trie[p].next[i]; temp = trie[p].Fail; while(temp != -1) { if(trie[temp].next[i]) { trie[k].Fail = trie[temp].next[i]; break; } temp = trie[temp].Fail; } if(temp == -1) trie[k].Fail = root; Q.push(k); } } } int Query(int root, int N, int num) { int sum = 0; int p = root, temp; for(int i=0; i<N; i++) { int k = MumStr[i]; while(!trie[p].next[k] && p!=root) p = trie[p].Fail; if(!trie[p].next[k])continue; temp = p = trie[p].next[k]; while(temp != root && trie[temp].num != num) { if(trie[temp].leaf) sum += 1; trie[temp].num = num; temp = trie[temp].Fail; } } return sum; } int main() { int N, M; while(scanf("%d", &N) != EOF) { int root = 0; trie[0].InIt(); top = 0; for(int i=1; i<=N; i++) { scanf("%s", s); int len = TurnStr(s, virus); Insert(root, len); } GetFail(root); scanf("%d", &M); for(int i=1; i<=M; i++) { scanf("%s", s); int len = TurnStr(s, MumStr); printf("%d\n", Query(root, len, i)); } printf("\n"); } return 0; }