ZOJ3430 Detect the Virus [AC自动机]

  这道题好坑啊,整整调了我一下午!!

  题意很简单,就是一个裸的自动机加上解码。编码是使用8位ASCII码连接字符,然后6位一取,结尾不足6位用0补上,每6位二进制数都会对应一个字符,形成了新的字符串。解码后最好用int存每一位的内容,写起来比较方便,因为可能会有'\0'这样的字符出现。。

  一开始写了个位运算版本的解码,但是一直WA。于是写了个很暴力的模拟二进制解码,竟然A了,看来自动机部分没什么问题。然后又回过头来调我的位运算版解码,怎么算都没有错啊,但是就是一直WAWAWA。。。。最后绝望之中改了下数组大小,把字符串数组从2500改成了5000。。。然后,然后就神奇的A了。。跑了130ms。。这尼玛是什么状况,难道2048bytes不是说2048位么。。就算不是,为啥越界不给我RE。。就算不给RE,为啥暴力的解码就过了。。。

  

#include <stdio.h>
#include <string.h>
#include <queue>
#define MAXN 40000
int n,m;
char ss[5000];
int sn[2500],slen,ctk[256];
//解码
void codestr(char* s){
    slen=0;
    for(int i=0,len=0,x=0;s[i]&&s[i]!='=';i++){
        len+=6, x=x<<6|ctk[s[i]];
        if(len>=8){
            sn[slen++]=((x>>(len-8))&0xff);
            len-=8;
        }
    }
}
//自动机
int next[MAXN][256],fail[MAXN],cnt[MAXN],cal[MAXN],pos;
int newnode(){
    for(int i=0;i<256;i++)next[pos][i]=0;
    fail[pos]=cnt[pos]=cal[pos]=0;
    return pos++;
}
void insert(int *s,int len,int id){
    int p=0;
    for(int i=0;i<len;i++){
        int &x=next[p][s[i]];
        p=x?x:x=newnode();
    }
    cnt[p]=id;
}
void makenext(){
    std::queue<int> q;
    q.push(0);
    while(!q.empty()){
        int u=q.front();q.pop();
        for(int i=0;i<256;i++){
            int v=next[u][i];
            if(v==0)next[u][i]=next[fail[u]][i];
            else q.push(v);
            if(u!=0)fail[v]=next[fail[u]][i];
        }
    }
}
int findvirus(int *s,int len,int id){
    int ans=0;
    for(int i=0,p=0;i<len;i++){
        p=next[p][s[i]];
        for(int f=p;f&&cal[f]!=id;f=fail[f]){
            cal[f]=id;
            if(cnt[f]>0)ans++;
        }
    }
    return ans;
}
int main(){
    for(int c=0;c<256;c++){
        if(c>='A'&&c<='Z')ctk[c]=c-'A';
        else if(c>='a'&&c<='z')ctk[c]=c-'a'+26;
        else if(c>='0'&&c<='9')ctk[c]=c-'0'+52;
        else if(c=='+')ctk[c]=62;
        else if(c=='/')ctk[c]=63;
    }
    //freopen("test.in","r",stdin);
    while(scanf("%d",&n)!=EOF){
        pos=0;newnode();
        for(int i=1;i<=n;i++){
            scanf("%s",ss);
            codestr(ss);
            insert(sn,slen,i);
        }
        makenext();
        scanf("%d",&m);
        for(int i=1;i<=m;i++){
            scanf("%s",ss);
            codestr(ss);
            int x=findvirus(sn,slen,i);
            printf("%d\n",x);
        }
        printf("\n");
    }
    return 0;
}
posted @ 2012-08-05 19:42  Burn_E  阅读(460)  评论(0编辑  收藏  举报