【题意】

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

【解题方法】

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

这题我咋死活过不了啊。最后连输入外挂都上了,还是TLE。可能是模板问题?我找了一份AC代码,先放上来,下来研究研究。可能是我的AC自动机太慢?

【别人的AC 代码】原创地址


#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;
}

【我的死活过不来了代码,下来研究研究】

#include <queue>
#include <cstdio>
#include <ctype.h>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxn = 5100100;
const int maxm = 500010;
const int maxs = 26;
char s[1010];
int nn;char s1[maxn],s2[maxn],s3[maxn];
int len2;
void read()
{
    char c;
    int p=0,t=0;
    while(c=getchar(),c!='\n')
    {
        if(t==0&&(c>='A'&&c<='Z'))
        {
            s1[p++]=c;
        }
        else if(t!=0&&(c>='A'&&c<='Z'))
        {
            while(t--)s1[p++]=c;
        }
        else if(c=='['||c==']')
        {
            t=0;
        }
        else if(c>='0'&&c<='9')
        {
            t=t*10+c-48;
        }
    }
    s1[p]='\0';
}
void change(){
    int len1=strlen(s1),num,i,j;
    len2=0;
    for(i=0;i<len1;i++){
        if(s1[i]>='A'&&s1[i]<='Z'){
            s2[len2++]=s1[i];
            continue;
        }
        if(s1[i]=='['){
            i++;
            num=0;
            for(;s1[i]>='0'&&s1[i]<='9';i++){
                num=num*10+s1[i]-'0';
            }
            int ll=len2;
            for(j=ll;j<ll+num;j++){
                s2[j]=s1[i];
                len2++;
            }
            i+=1;
        }
    }
    s2[len2]='\0';
    for(i=0;i<len2;i++){
        s3[i]=s2[len2-i-1];
    }
    s3[len2]='\0';
}
struct Acautomata{
    int root,sz;
    int nxt[maxm][maxs],fail[maxm],cnt[maxm];
    int newnode()
    {
        cnt[sz]=0;
        memset(nxt[sz],-1,sizeof(nxt[0]));
        return sz++;
    }
    void init()
    {
        sz=0;
        root=newnode();
    }
    void Insert(char *s)
    {
        int u=root,n=strlen(s);
        for(int i=0; i<n; i++)
        {
            int &v=nxt[u][s[i]-'A'];
            if(v==-1) v=newnode();
            u=v;
        }
        ++cnt[u];
    }
    void build()
    {
        queue<int>q;
        fail[root]=root;
        for(int i=0; i<maxs; i++){
            int &v=nxt[root][i];
            if(~v){
                fail[v]=root;
                q.push(v);
            }else{
                v=root;
            }
        }
        while(q.size())
        {
            int u=q.front();q.pop();
            for(int i=0; i<maxs; i++)
            {
                int &v=nxt[u][i];
                if(~v){
                    fail[v]=nxt[fail[u]][i];
                    q.push(v);
                }else{
                    v=nxt[fail[u]][i];
                }
            }
        }
    }
    int queryans(char *s)
    {
        int u=root,n=strlen(s);
        int ans=0;
        for(int i=0; i<n; i++)
        {
            u=nxt[u][s[i]-'A'];
            for(int v=u; v!=root; v=fail[v]){
                ans+=cnt[v];
                cnt[v]=0;
            }
        }
        return ans;
    }
}ac1;
int main()
{
    int T;
    scanf("%d",&T);
    while(T--)
    {
        scanf("%d",&nn);
        ac1.init();
        for(int i=1; i<=nn; i++)
        {
            scanf("%s",s);
            ac1.Insert(s);
        }
        getchar();
        ac1.build();
        read();
        //cout<<s1<<endl;
        change();
        int ans = 0;
        ans += ac1.queryans(s2);
        ans += ac1.queryans(s3);
        printf("%d\n",ans);
    }
    return 0;
}