ZOJ 3228. Searching the String (AC自动机)

题目: http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=3441

题意:
给定一个长串;
给定n个询问,每个询问给定询问类型和一个段串;
有两种询问类型:
0类型要求输出短串在长串中出现的次数(允许重叠);
1类型要求输出短串在长串中出现的次数(不允许重叠)。

分析:
允许重叠的容易,裸的AC自动机;
不允许重叠的只需这样处理:
记录trie树上每个结尾节点一次匹配是在长串的哪个位置,若这次与上次不重叠则记录。

代码:

#include <bits/stdc++.h>
using namespace std;
typedef long long llong;
const int tmax=1e5+5;
struct question{
    int kind,index;
    char s[10];
};
question data[tmax];
struct AC{
    int num,ch[6*tmax][30],f[6*tmax],last[6*tmax],val[6*tmax];
    int times[6*tmax][2],dep[7*tmax],pos[6*tmax];
    void init()
    {
        num=0;
        memset(ch,0,sizeof(ch));
        memset(f,0,sizeof(f));
        memset(last,0,sizeof(last));
        memset(val,0,sizeof(val));
        memset(times,0,sizeof(times));
        memset(dep,0,sizeof(dep));
        memset(pos,-1,sizeof(pos));
        return;
    }
    void insert(char *s,int qN)
    {
        int u=0,len=strlen(s),id;
        for(int i=0;i<len;i++)
        {
            id=s[i]-'a';
            if(!ch[u][id]) ch[u][id]=++num;
            u=ch[u][id];
        }
        val[u]=1;
        dep[u]=len;
        data[qN].index=u;
        return;
    }
    void getfail()
    {
        queue<int> Q;
        Q.push(0);
        int x,u,v;
        while(!Q.empty())
        {
            x=Q.front();Q.pop();
            for(int i=0;i<26;i++)
            {
                u=ch[x][i];
                if(!u)
                {
                    ch[x][i]=ch[f[x]][i];
                    continue;
                }
                Q.push(u);
                if(x==0) continue;
                v=f[x];
                while(v&&!ch[v][i]) v=f[v];
                f[u]=ch[v][i];
                last[u]=val[f[u]]?f[u]:last[f[u]];
            }
        }
        return;
    }
    void find(char *s)
    {
        memset(times,0,sizeof(times));
        int len=strlen(s),u=0,id,j;
        for(int i=0;i<len;i++)
        {
            id=s[i]-'a';
            u=ch[u][id];
            j=u;
            do{
                times[j][0]++;
                if(i-pos[j]>=dep[j])
                {
                    times[j][1]++;
                    pos[j]=i;
                }
                j=last[j];
            }while(j);
        }
        return;
    }
}ac;

int main()
{
    char s[tmax];
    int q,kase=0;
    while(scanf("%s",s)==1)
    {
        ac.init();
        scanf("%d",&q);
        for(int i=1;i<=q;i++)
        {
            scanf("%d %s",&data[i].kind,data[i].s);
            ac.insert(data[i].s,i);
        }
        ac.getfail();
        ac.find(s);
        printf("Case %d\n",++kase);
        for(int i=1;i<=q;i++)
            if(data[i].kind==0)
                printf("%d\n",ac.times[data[i].index][0]);
            else
                printf("%d\n",ac.times[data[i].index][1]);
        printf("\n");
        getchar();
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值