HDOJ 3695 Computer Virus on Planet Pandora (AC自动机)

题意:给n个病毒字符串和一个程序字符串,若程序字符串包含某个病毒字符串或者它的反串,则包含这个病毒,问所给程序字符串包含多少个病毒?

分析:用病毒串和反串建立AC自动机,然后求包含多少病毒,但同一个病毒可能会被计算2次(如果病毒和它的反串都出现在程序中),对于每个病毒,它在自动机中都有2个结点代表自身结尾和反串结尾,我们对每个病毒都记录这2个结点,在统计的过程中可以把走过的结点打上标记,最后再统计哪些病毒的2个结点都被标记,说明被统计了2次,需要减去一次,这样就没问题了。但是题中说了程序串是压缩的,所以需要先需处理,而且还要考虑嵌套压缩的情况,当时就没考虑到……

View Code
#include <stdio.h>
#include <string.h>
#include <queue>
using namespace std;
#define N 251
#define NODE 500010
#define LEN 5100010
int n,node,x[N],y[N];
int next[NODE][26],fail[NODE],cnt[NODE];
bool vis[NODE];
char S[LEN],tmp[LEN];
int newnode()
{
    memset(next[node],0,sizeof(next[0]));
    fail[node]=cnt[node]=0;
    return node++;
}
void insert(char *s,int id)
{
    int i,k,cur;
    for(i=cur=0; s[i]; i++)
    {
        k=s[i]-'A';
        if(!next[cur][k])   next[cur][k]=newnode();
        cur=next[cur][k];
    }
    cnt[cur]++;
    x[id]=cur;
    for(i--,cur=0; i>=0; i--)
    {
        k=s[i]-'A';
        if(!next[cur][k])   next[cur][k]=newnode();
        cur=next[cur][k];
    }
    cnt[cur]++;
    y[id]=cur;
}
void makenext()
{
    queue<int>q;
    int u,v,k;
    q.push(0);
    while(!q.empty())
    {
        u=q.front(),q.pop();
        for(int k=0; k<26; k++)
        {
            v=next[u][k];
            if(v)   q.push(v);
            else    next[u][k]=next[fail[u]][k];
            if(u&&v)    fail[v]=next[fail[u]][k];
        }
    }
}
void read()
{
    char c;
    int p=0,t=0;
    while(c=getchar(),c!='\n')
    {
        if(t==0&&(c>='A'&&c<='Z'))
        {
            S[p++]=c;
        }
        else if(t!=0&&(c>='A'&&c<='Z'))
        {
            while(t--)S[p++]=c;
        }
        else if(c=='['||c==']')
        {
            t=0;
        }
        else if(c>='0'&&c<='9')
        {
            t=t*10+c-48;
        }
    }
    S[p]='\0';
}
int main()
{
    int T;
    char s[1001];
    scanf("%d",&T);
    while(T--)
    {
        node=0,newnode();
        scanf("%d",&n);
        for(int i=0; i<n; i++)
        {
            scanf("%s\n",s);
            insert(s,i);
        }
        makenext();
        read();

        int ans=0,i,k,cur;
        memset(vis,0,sizeof(vis));
        for(i=cur=0; S[i]; i++)
        {
            k=S[i]-'A';
            cur=next[cur][k];
            for(int t=cur; t&&cnt[t]!=-1; t=fail[t])
            {
                ans+=cnt[t];
                cnt[t]=-1;
                vis[t]=1;
            }
        }
        for(int i=0; i<n; i++)
        {
            if(vis[x[i]]&&vis[y[i]])    ans--;
        }
        printf("%d\n",ans);
    }
    return 0;
}
posted @ 2012-09-14 23:17  BeatLJ  阅读(278)  评论(0编辑  收藏  举报