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
【AC自动机】统计单词出现个数
最新推荐文章于 2021-08-12 19:08:15 发布