【AC自动机】统计单词出现个数

hz2016评测《==点

caioj.cn《==点
#include<map>
#include<queue>
#include<cmath>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<iostream>
#include<algorithm>
#define Maxchar 1000000
#define Maxm 10000
#define Maxn 50
#define Maxs 26
#define mes(x,y) memset(x,y,sizeof(x));
#define mpy(x,y) memcpy(x,y,sizeof(x))
#define INF 2147483647
using namespace std;
struct Tire{
    int s,c[Maxs+1],fail;
    Tire(){
        s=fail=0;
        mes(c,-1);
    }
}t[Maxn*Maxm+1];//字典树 
int T,tot,ans,n;
char a[Maxchar+1];
void clean(int x){
    t[x].s=t[x].fail=0;
    for(int i=1;i<=Maxs;i++)t[x].c[i]=-1;//清空字典树节点 
}
void bt(int root){
    int x=root,len=strlen(a+1);//建字典树 
    for(int i=1;i<=len;i++){//len个字符依次建节点 
        int y=a[i]-'a'+1;//把字符换成值 
        if(t[x].c[y]==-1){//如果没有节点 
            t[x].c[y]=++tot;//给新的节点一个新编号 
            clean(tot);//先给他清空再给节点 
        }
        x=t[x].c[y];//我来新建的节点继续建 
    }
    t[x].s++;//记录下再节点这个位置结尾,就是这个字符串的结尾的位置是这个节点的个数,有点啰嗦,自己意会一下。 
}
queue<int> q;
void bfs(){
    q.push(0);
    while(q.empty()==0){//bfs循环找节点 
        int x=q.front();
        for(int i=1;i<=Maxs;i++){
            int son=t[x].c[i];//在树上做kmp 
            if(son==-1)continue;//找存在的节点 
            if(x==0)t[son].fail=0;
            else{
                int j=t[x].fail;
                while(j!=0&&t[j].c[i]==-1)j=t[j].fail;//fail就是kmp的p数组然后一个一个跳 
                t[son].fail=max(t[j].c[i],0);//看看存不存在,不存在指向0,就是kmp的else p[i]=0; 
            }
            q.push(son); 
        }
        q.pop();
    }
}
void solve(){
    int x=0,len=strlen(a+1),j;
    for(int i=1;i<=len;i++){//在树上查找 
        int y=a[i]-'a'+1;
        while(x!=0&&t[x].c[y]==-1)x=t[x].fail;//再找一下和这句话有没有匹配的,有的话++ 
        x=t[x].c[y];
        if(x==-1){x=0;continue;}
        j=x;
        while(t[j].s!=0){
            ans+=t[j].s;//s就是用来记录有多少个符合的。 
            t[j].s=0;
            j=t[j].fail;
        }
    }
    printf("%d\n",ans);
}
int main(){
    scanf("%d",&T);
    while(T--){
        ans=tot=0;
        scanf("%d",&n);
        clean(0);
        for(int i=1;i<=n;i++){
            scanf("%s",a+1);
            bt(0);
        }
        bfs();
        scanf("%s",a+1);
        solve();
    }
    return 0;
}
这题还是边看代码边理解把,ac自动机是建立在Tire就是字典树的基础上,大家可以先去学一下字典树,可惜暂时没有字典树的题。 就先练一下ac自动机吧,noip可能出的(某dalao:不出我当场吃尸米) 所以大家好好背模版。  

查看原文:http://hz2016.tk/blog/?p=25
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值