ZOJ 3430 detect the virus AC自动机

#include<stdio.h>
#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
int n,m,alen,blen,a[5100],b[5600];
struct ACatuomata{
    int next[55600][256],fail[55600],idx[55600],last[55600],num,root;
    bool vis[55600];
    int newnode()
    {
        memset(next[num],0,sizeof next[num]);
        idx[num]=0;
        return num++;
    }
    void init()
    {
        num=0;
        root=newnode();
    }
    void insert(int *s,int len,int id)
    {
        int cur=root;
        for(int i=0;i<len;++i)
        {
            int &tmp=next[cur][s[i]];
            if(!tmp)tmp=newnode();
            cur=tmp;
        }
        idx[cur]=id;
    }
    void getfail()
    {
        queue<int>q;
        fail[root]=root;
        for(int i=0;i<256;++i)
        {
            int u=next[root][i];
            if(u)
            {
                last[u]=fail[u]=0;
                q.push(u);
            }
        }
        while(!q.empty())
        {
            int cur=q.front();
            q.pop();
            for(int i=0;i<256;++i)
            {
                int u=next[cur][i];
                if(u)
                {
                    fail[u]=next[fail[cur]][i];
                    last[u]=idx[fail[u]]?fail[u]:last[fail[u]];
                    q.push(u);
                }
                else next[cur][i]=next[fail[cur]][i];
            }
        }
    }
    int query(int *s,int len)
    {
        memset(vis,0,sizeof vis);
        int cur=root,ret=0;
        for(int i=0;i<len;++i)
        {
            cur=next[cur][s[i]];
            int tmp=cur;
            while(tmp!=root)
            {
                vis[idx[tmp]]=1;
                tmp=last[tmp];
            }
        }
        for(int i=1;i<=n;++i)
            ret+=vis[i];
        return ret;
    }
}ac;
int DecodeIndex[]=
{
    0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
    0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,
    0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x3E,0x40,0x40,0x40,0x3F,
    0x34,0x35,0x36,0x37,0x38,0x39,0x3A,0x3B,0x3C,0x3D,0x40,0x40,0x40,0x40,0x40,0x40,
    0x40,0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,
    0x0F,0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x40,0x40,0x40,0x40,0x40,
    0x40,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F,0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,
    0x29,0x2A,0x2B,0x2C,0x2D,0x2E,0x2F,0x30,0x31,0x32,0x33,0x40,0x40,0x40,0x40,0x40
};
void Base64Decode(int* src,int* dest,int srclen)
{
    for(int i=0;i!=srclen/4;i++)
    {
        *dest=((DecodeIndex[*src]<<2)|((DecodeIndex[*(src+1)]&0x30)>>4))%256;
        *(dest+1)=((DecodeIndex[*(src+1)]<<4)|((DecodeIndex[*(src+2)]&0x3C)>>2))%256;
        *(dest+2)=(((DecodeIndex[*(src+2)]&0x03)<<6)|(DecodeIndex[*(src+3)]&0x3F))%256;
        src+=4;
        dest+=3;
    }
}
int main()
{
    while(~scanf("%d",&n))
    {
        ac.init();
        getchar();
        for(int i=1;i<=n;++i)
        {
            char c;
            while(c=getchar())
            {
                if(c=='\n')break;
                a[alen++]=c;
                if(c=='=')++blen;
            }
            Base64Decode(a,b,alen);
            blen=alen/4*3-blen;
            ac.insert(b,blen,i);
            alen=blen=0;
        }
        ac.getfail();
        scanf("%d",&m);
        getchar();
        while(m--)
        {
            char c;
            while(c=getchar())
            {
                if(c=='\n')break;
                a[alen++]=c;
                if(c=='=')++blen;
            }
            Base64Decode(a,b,alen);
            blen=alen/4*3-blen;
            printf("%d\n",ac.query(b,blen));
            alen=blen=0;
        }
        puts("");
    }
}

题意:给出n个匹配串,有m个询问,对于每个询问,会给出一个原串,求原串中出现过几种匹配串。
这个题的匹配串和原串都是加了密的需要自己解密。
比较坑的就是他问的是种类而不是次数。
比如匹配串ab,原串abab,也只会返回1。
所以这个就不能保存cnt然后扫描的时候cnt++
这个题同样不能break。
就多加一个vis数组,也同样保存匹配串的下标,然后把vis[下标]设为1,最后统计有多少vis为1的就是答案,记得每次询问要清空vis。
错了很多次,不过都是没搞懂题意的时候为了弄懂题意而错的。。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值