zoukankan      html  css  js  c++  java
  • AC自动机模板2(【CJOJ1435】)

    题面

    Description

    对,这就是裸的AC自动机。
    要求:在规定时间内统计出模版字符串在文本中出现的次数。

    Input

    第一行:模版字符串的个数N。
    第2->N+1行:N个字符串。(每个模版字符串的长度<=50)
    第N+2行:一行很长的字符串。长的很。(使用AC自动机能在1s内计算出)

    Output

    共N行,每行输出一个模版及出现的次数。(之间有一个空格,按照输入顺序输出)

    Sample Input

    4
    hers
    her
    his
    she
    shershisher

    Sample Output

    hers 1
    her 2
    his 1
    she 2

    Hint

    所有字母均为小写
    所给模版不会重复

    题解

    和前面Luogu那一道AC自动机的模板相同
    只是要求解的东西不同。
    到时候写完了AC自动机的详解再来粘链接

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<queue>
    #include<algorithm>
    using namespace std;
    struct Tree//字典树 
    {
    	 int fail;//失配指针
    	 int vis[26];//子节点的位置
    	 int end;//标记以这个节点结尾的单词编号 
    }AC[1000000];//Trie树
    int cnt=0;//Trie的指针 
    int Ans[1000000];//所有单词的出现次数 
    string s[1000000];
    inline void Build(string s,int Num)
    {
    	    int l=s.length();
    	    int now=0;//字典树的当前指针 
    	    for(int i=0;i<l;++i)//构造Trie树
    		{
    			    if(AC[now].vis[s[i]-'a']==0)//Trie树没有这个子节点
    				   AC[now].vis[s[i]-'a']=++cnt;//构造出来
    				now=AC[now].vis[s[i]-'a'];//向下构造 
    	    }
    	    AC[now].end=Num;//标记单词结尾 
    }
    void Get_fail()//构造fail指针
    {
    	    queue<int> Q;//队列 
    	    for(int i=0;i<26;++i)//第二层的fail指针提前处理一下
            {
            	   if(AC[0].vis[i]!=0)
            	   {
            	       AC[AC[0].vis[i]].fail=0;//指向根节点
    				   Q.push(AC[0].vis[i]);//压入队列 
    			   }
    	    }
    	    while(!Q.empty())//BFS求fail指针 
    	    {
    	    	  int u=Q.front();
    	    	  Q.pop();
    			  for(int i=0;i<26;++i)//枚举所有子节点
    			  {
    			  	      if(AC[u].vis[i]!=0)//存在这个子节点
    					  {
    					  	      AC[AC[u].vis[i]].fail=AC[AC[u].fail].vis[i];
    					  	          //子节点的fail指针指向当前节点的
    								  //fail指针所指向的节点的相同子节点 
    					  	      Q.push(AC[u].vis[i]);//压入队列 
    					  }
    					  else//不存在这个子节点 
    					  AC[u].vis[i]=AC[AC[u].fail].vis[i];
    					  //当前节点的这个子节点指向当
    					  //前节点fail指针的这个子节点 
    		      }
    	    }
    }
    int AC_Query(string s)//AC自动机匹配
    {
    	    int l=s.length();
    	    int now=0,ans=0;
    	    for(int i=0;i<l;++i)
    	    {
    	    	    now=AC[now].vis[s[i]-'a'];//向下一层
    				for(int t=now;t;t=AC[t].fail)//循环求解
    					     Ans[AC[t].end]++;
    	    }
    	    return ans;
    }
    int main()
    {
    	 int n;
         cin>>n;
         for(int i=1;i<=n;++i)
         {
         	    cin>>s[i];
         	    Build(s[i],i);
         }
         AC[0].fail=0;//结束标志 
         Get_fail();//求出失配指针
         cin>>s[0];//文本串 
    	 AC_Query(s[0]);
    	 for(int i=1;i<=n;++i)
    	 {
    	 	    cout<<s[i]<<' ';
    	 	    cout<<Ans[i]<<endl;
    	 }
    	 return 0;
    }
    
    
  • 相关阅读:
    Vue 框架怎么实现对象和数组的监听?
    能说下 vue-router 中常用的 hash 和 history 路由模式实现原理吗?
    vue-router 路由模式有几种?
    Vue 组件间通信有哪几种方式?
    v-model 的原理?
    华硕笔记本修复
    linux下制作u盘启动盘
    virtualbox不能启动虚拟机
    ubuntu14.04建立wifi热点
    git中文文件名和中文目录显示乱码
  • 原文地址:https://www.cnblogs.com/cjyyb/p/7196420.html
Copyright © 2011-2022 走看看