ZOJ3228 - Searching the String(AC自动机)

题目大意

给定一个文本串,接下来有n个模式串,每次查询模式串出现的次数,查询分两种,可重叠和不可重叠

题解

第一次是把AC自动机构造好,跑n次,统计出每个模式串出现的次数,交上去果断TLE。。。后来想想其实只要跑一次文本串即可。。。

这个题目主要的问题是要解决有可重叠和不可重叠两种情况,用一个数组记录下模式串上一次出现的位置就可以判断是否重叠了

代码:

#include <cstdio>

#include <iostream>

#include <algorithm>

#include <queue>

#include <vector>

#include <cstring>

using namespace std;

#define MAXN 100005

const int maxnode=600005;

const int sigma_size=26;

char T[MAXN],s[7];

bool flag[MAXN];

int pos[MAXN];

struct  Triegragh

{

    int ch[maxnode][sigma_size];

    int fail[maxnode];

    int deep[maxnode];

    int cnt[maxnode][2];

    int end[maxnode];

    int last[maxnode];

    int val[maxnode];

    int sz;

    void init()

    {

        sz=1;

        memset(ch[0],0,sizeof(ch[0]));

        memset(cnt,0,sizeof(cnt));

        memset(end,-1,sizeof(end));

        memset(val,0,sizeof(val));

    }

    int idx(char c){return c-'a';}

    int insert(char *s)

    {

        int u=0,n=strlen(s);

        for(int i=0;i<n;i++)

        {

            int c=idx(s[i]);

            if(!ch[u][c])

            {

                memset(ch[sz],0,sizeof(ch[sz]));

                val[sz]=0;

                deep[sz]=i+1;

                ch[u][c]=sz++;

            }

            u=ch[u][c];

        }

        val[u]++;

        return u;

    }

    void getfail()

    {

        queue<int>q;

        fail[0]=0;

        for(int c=0;c<sigma_size;c++)

        {

            int u=ch[0][c];

            if(u){fail[u]=0;q.push(u);last[u]=0;} 

        }

        while(!q.empty())

        {

            int r=q.front();q.pop();

            for(int c=0;c<sigma_size;c++)

            {

                int u=ch[r][c];

                if(!u){ch[r][c]=ch[fail[r]][c];continue;}

                q.push(u);

                fail[u]=ch[fail[r]][c];

                last[u]=val[fail[u]]?fail[u]:last[fail[u]];

            }

        }

    }

    void count(int j,int i)

    {

        if(j)

        {

            cnt[j][0]++;

            if(i-end[j]>=deep[j])

            {

                cnt[j][1]++;

                end[j]=i;

            }

            count(last[j],i);

        }

    }

    void find(char *T)

    {

        int j=0,n=strlen(T);

        for(int i=0;i<n;i++)

        {

            int c=idx(T[i]);

            j=ch[j][c];

            if(val[j])

                count(j,i);

            else 

                if(last[j]) count(last[j],i);

        }

    }

};

Triegragh ac;

int main()

{

    int kase=0; 

    while(scanf("%s",T)!=EOF)

    {

        printf("Case %d\n",++kase);

        int n;

        scanf("%d",&n);

        ac.init();

        for(int i=1;i<=n;i++)

        {

            scanf("%d%s",&flag[i],s);

            pos[i]=ac.insert(s);

        }

        ac.getfail();

        ac.find(T);

        for(int i=1;i<=n;i++)

            printf("%d\n",ac.cnt[pos[i]][flag[i]]);

        printf("\n");

    }

    return 0;

}

你可能感兴趣的:(String)