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;

}

你可能感兴趣的:(AC自动机)