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

做比赛的时候看这题就感觉是自动机,当时只是听说过有这个算法,但是根本没看过,晚上回去以后找教程看了一下复制了hh大神的模版,又自己敲了一下模版题,终于弄明白一点了,今天又做了一下F题这题和我做的那个模版题挺像的,不过就是多了反转以后的匹配和字符串的转换,其他的就是套模版而已。现在我也只能套模版,网上的英文教程看的云里雾里的,算了先搞个模版再说吧……
#include <cstdio>
#include <iostream>
#include <cstring>
#include <ctype.h>
using namespace std;
//MAX_NODE = StringNumber * StringLength
const int MAX_NODE = 250001;
//节点个数,一般字符形式的题26个
const int CHILD_NUM = 26;
//特定题目需要
class ACAutomaton
{
private:
    int isword[MAX_NODE];
    //每个节点的儿子,即当前节点的状态转移
    int chd[MAX_NODE][CHILD_NUM];
    //传说中的fail指针
    int fail[MAX_NODE];
    //队列,用于广度优先计算fail指针
    int Q[MAX_NODE];
    //字母对应的ID
    int ID[128];
    //已使用节点个数
    int sz;
public:
    //初始化,计算字母对应的儿子ID,如:'a'->0 ... 'z'->25
    void Initialize()
    {
        fail[0] = 0;
        for (int i = 0 ; i < CHILD_NUM ; i ++)
        {
            ID[i+'A'] = i;//当前匹配的字符集,根据题意进行修改,一开始没注意是大写字母,一直不对……
        }
    }
    //重新建树需先Reset
    void Reset()
    {
        memset(chd[0] , 0 , sizeof(chd[0]));
        memset(isword,-1,sizeof(isword));
        sz = 1;
    }
    //将权值为key的字符串a插入到trie中
    void Insert(char *a)
    {
        int p = 0;
        for ( ; *a ; a ++)
        {
            int c = ID[*a];
            if (!chd[p][c])
            {
                memset(chd[sz] , 0 , sizeof(chd[sz]));
                chd[p][c] = sz ++;
            }
            p = chd[p][c];
        }
        isword[p]=1;
    }
    //建立AC自动机,确定每个节点的权值以及状态转移
    void Construct()
    {
        int *s = Q , *e = Q;
        for (int i = 0 ; i < CHILD_NUM ; i ++)
        {
            if (chd[0][i])
            {
                fail[ chd[0][i] ] = 0;
                *e ++ = chd[0][i];
            }
        }
        while (s != e)
        {
            int u = *s++;
            for (int i = 0 ; i < CHILD_NUM ; i ++)
            {
                int &v = chd[u][i];
                if (v)
                {
                    *e ++ = v;
                    fail[v] = chd[ fail[u] ][i];
                }
                else
                {
                    v = chd[ fail[u] ][i];
                }
            }
        }
    }
    int work(char *a)
    {
        int ret = 0 , p = 0;
        for(int c = ID[*a] ; *a ; ++ a  , c = ID[*a])
        {
            p = chd[p][c];
            int pp = p;
            while(pp && isword[pp] != -1)
            {
                ret += isword[pp];
                isword[pp] = -1;
                pp = fail[pp];
            }
        }
        return ret;
    }
} AC;
void transform(char s1[],char s2[])
{
    int len=strlen(s1);
    int p=0;
    for(int i=0; i<len; i++)
    {
        if(s1[i]=='[')
        {
            i++;
            int temp=0;
            for(; isdigit(s1[i]); i++)
            {
                temp=temp*10+s1[i]-'0';
            }
            for(int j=0; j<temp; j++)
                s2[p++]=s1[i];
            i++;
        }
        else s2[p++]=s1[i];
    }
    s2[p]='\0';
}
char temp[5100005],convert[5100005],str[5100005];
char change[5100005];
int main()
{
    //freopen("input.txt","r",stdin);
    AC.Initialize();
    int t;
    scanf("%d",&t);
    while(t--)
    {
        AC.Reset();
        int n;
        scanf("%d",&n);
        for(int k=0; k<n; k++)
        {
            scanf("%s",temp);
            transform(temp,convert);
            AC.Insert(convert);
        }
        AC.Construct();
        scanf("%s",str);
        int len=strlen(str);
        transform(str,change);
        int ans=AC.work(change);
        len=strlen(change);
        for(int i=0,j=len-1; i<j; i++,j--)
        {
            swap(change[i],change[j]);
        }
        ans+=AC.work(change);
        printf("%d\n",ans);
    }
    return 0;
}

你可能感兴趣的:(HDU 3695 Computer Virus on Planet Pandora(AC自动机))