• 「LuoguP3808」 【模板】AC自动机(简单版)


    题目背景

    通过套取数据而直接“打表”过题者,是作弊行为,发现即棕名。

    这是一道简单的AC自动机模板题。

    用于检测正确性以及算法常数。

    为了防止卡OJ,在保证正确的基础上只有两组数据,请不要恶意提交。

    管理员提示:本题数据内有重复的单词,且重复单词应该计算多次,请各位注意

    题目描述

    给定n个模式串和1个文本串,求有多少个模式串在文本串里出现过。

    输入输出格式

    输入格式:

    第一行一个n,表示模式串个数;

    下面n行每行一个模式串;

    下面一行一个文本串。

    输出格式:

    一个数表示答案

    输入输出样例

    输入样例#1: 复制
    2
    a
    aa
    aa
    输出样例#1: 复制
    2

    说明

    subtask1[50pts]:∑length(模式串)<=10^6,length(文本串)<=10^6,n=1;

    subtask2[50pts]:∑length(模式串)<=10^6,length(文本串)<=10^6;


     题解

    在通常就没什么人认真听的集训里,qwerta刚撸完一把Win7原装的扫雷,舒适的抬起头,正好对上了老师讲fail树的眼神。

    所以是懂一丢丢手推方法的。

    建议大家先构造点小数据手推,像是什么在$her,him,he,his,she$上匹配$shehisher$之类的。

    网上教程也蛮多,就不画图了。(懒

    其实是自己也推不蛮清楚

    然后是教材QAQ yyb大佬的博客

    总之,AC自动机就是在trie树上bfs一下然后乱搞,可以理解为trie上的KMP叭。

    自己都不怎么会,就不讲这个东西了QAQ

     1 #include<queue>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<iostream>
     5 using namespace std;
     6 #define R register
     7 const int MAXL=1e6+3;
     8 char s[MAXL];
     9 struct emm{
    10     int fail;
    11     int nxt[26];
    12     int tag;
    13 }AC[MAXL];//Tree结构体
    14 queue<int>q;//get_fail的时候用的queue
    15 int main()
    16 {
    17     //freopen("a.in","r",stdin);
    18     ios::sync_with_stdio(false);
    19     cin.tie(false);cout.tie(false);
    20     int n;
    21     cin>>n;
    22     int tot=0;
    23     //trie
    24     while(n--)
    25     {
    26         cin>>s;
    27         int len=strlen(s);
    28         int now=0;//now表示当前的节点编号
    29         for(R int i=0;i<len;++i)
    30         {
    31             if(!AC[now].nxt[s[i]-'a'])//如果当前节点没有这个儿子
    32               AC[now].nxt[s[i]-'a']=++tot;//就造个儿子
    33             now=AC[now].nxt[s[i]-'a'];//now跳到这个儿子上
    34         }
    35         AC[now].tag++;//now最后在的地方是这个模式串的结束点,标记一下
    36     }
    37     //get_fail
    38     {
    39         //首先把跟0号节点相连的点处理一下
    40         for(R int i=0;i<26;++i)
    41         {
    42             if(AC[0].nxt[i])//如果这个儿子存在
    43             {
    44                 AC[AC[0].nxt[i]].fail=0;//把fail指向0号节点(其实默认就是0啊QAQ
    45                 q.push(AC[0].nxt[i]);//把这个儿子push进去
    46             }    
    47         }
    48         while(!q.empty())
    49         {
    50             int x=q.front();q.pop();//取点
    51             for(R int i=0;i<26;++i)
    52             {
    53                 if(AC[x].nxt[i])//如果这个儿子存在
    54                 {
    55                     AC[AC[x].nxt[i]].fail=AC[AC[x].fail].nxt[i];//敲重点!!!
    56                     //这个儿子的fail,等于这个节点fail的儿子   会手推就能懂叭QAQ
    57                     q.push(AC[x].nxt[i]);//push进去
    58                 }
    59                 else
    60                   AC[x].nxt[i]=AC[AC[x].fail].nxt[i];//这里直接把nxt指向了fail的对应儿子
    61             }
    62         }
    63     }
    64     //run
    65     cin>>s;
    66     long long ans=0;
    67     int len=strlen(s);
    68     int now=0;//now表示当前节点编号
    69     for(R int i=0;i<len;++i)
    70     {
    71         now=AC[now].nxt[s[i]-'a'];//往下走一层(因为之前直接把空的nxt往fail指了,所以不需要通常的while跳fail
    72 //大概就是Trie图和Trie树的区别了叭
    73         for(R int t=now;t&&AC[t].tag!=-1;t=AC[t].fail)//从这个点开始暴力跳fail,找匹配
    74         {
    75             ans+=AC[t].tag;
    76             AC[t].tag=-1;//这是个剪枝
    77         }
    78     }
    79     cout<<ans;
    80     return 0;//撒花
    81 }

    然后吐槽一下咕咕的数据,之前有一大段把$now$和$i$混用了,结果还过了一个点(???

  • 相关阅读:
    微信公众号教程(5)自动回复操作案例
    微信公众号教程(4)微信公众平台编辑模式介绍
    微信公众号教程(3)微信公众平台群发消息
    微信公众号教程(2)微信公众平台后台介绍
    微信公众号教程(1)微信公众账号注册、设置、登陆
    二级c程序设计题(2)
    二级c程序设计题(1)
    C++经典编程题#6:分配病房
    C++经典编程题#5:寻找下标
    python-----面向对象三大特性
  • 原文地址:https://www.cnblogs.com/qwerta/p/9751774.html
Copyright © 2020-2023  润新知