ZOJ3228

题目大意

给定一个文本串,接下来有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
",++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
",ac.cnt[pos[i]][flag[i]]);
        printf("
");
    }
    return 0;
}
原文地址:https://www.cnblogs.com/zjbztianya/p/3341682.html