美文网首页
LUOGU3976 AC自动机

LUOGU3976 AC自动机

作者: 苏子旃 | 来源:发表于2019-02-16 15:09 被阅读0次

LUOGU3808
LUOGU3976
Description
N个由小写字母组成的模式串以及一个文本串T。每个模式串可能会在文本串中出现多次。你需要找出哪些模式串在文本串T中出现的次数最多。
Input Format
输入含多组数据。
每组数据的第一行为一个正整数N,表示共有N个模式串,1 \leq N \leq 150
接下去N行,每行一个长度小于等于70的模式串。下一行是一个长度小于等于10^6的文本串T
输入结束标志为N=0

Output Format
对于每组数据,第一行输出模式串最多出现的次数,接下去若干行每行输出一个出现次数最多的模式串,按输入顺序排列。

Sample Input

2
aba
bab
ababababac
6
beta
alpha
haha
delta
dede
tata
dedeltalphahahahototatalpha
0

Sample Output

4
aba
2
alpha
haha

Constraints
见题面。

CCYOS
这是一道AC自动机的板子题。

AC自动机 可以理解为在Trie图上的KMP算法。

这是一棵trie树
对于正常的遍历,每次在这棵树上搜索的时候会因为回溯而浪费大量时间。因此我们考虑对它进行优化,直接建立“树边”:搜索时,在当前节点的儿子中下一个字符失配时,能够快速地跳转到下一个可以匹配下一个字符的节点,也就是当前可匹配的最长后缀。
设当前节点为i,则当前节点的“树边”指向nxt[i]
建立nxt数组
举一个更详细的例子: 详细的例子
对文本串 ader 进行匹配时,发现在匹配至8号节点时失配,于是直接跳转到10号节点继续进行匹配。
如何建立nxt数组 - get_nxt
根节点的后继是0,根节点的直接下属结点的后继也是0。(重新开始匹配)
余下的结点的后继:设到节点x上的边的字符为k,父亲结点为f,则nxt[x] = ch[nxt[f]][k]

code

inline void get_nxt(){
  int now = 0;
  queue<int> q;while(q.size())q.pop();
  for(int i = 0;i < 26;++i)if(ch[0][i])q.push(ch[0][i]);
  while(q.size()){
    now = q.front();q.pop();
    for(int i = 0;i < 26;++i){
      if(ch[now][i])q.push(ch[now][i]),nxt[ch[now][i]] = ch[nxt[now]][i];
      else ch[now][i] = ch[nxt[now]][i];
    }
  }
}

trie树的建立
先沿着树搜索,在空点处加点,标记最后一个字符声明这是一个字符串的结尾。记树的节点数为cnt

code

int cnt;
inline void build(char* s){
  int now = 0,len = strlen(s);
  for(int i = 0;i < len;++i){
    int c = s[i] - 'a';
    if(!ch[now][c])ch[now][c] = ++cnt;
    now = ch[now][c];
  }
  ed[now] = 1;
}

trie树的搜索
计数式:沿着树搜索,向下一层,搜索后继结点计数。
bool式:勇就完事了。

code

//计数式
inline void ask(char* s){
  int now = 0,len = strlen(s);
  for(int i = 0;i < len;++i){
    now = ch[now][s[i] - 'a'];
    for(int t = now;t;t = nxt[t])ans[ed[t]]++;
  }
}
//bool式
inline bool ask(char* s){
  int len = strlen(s),now = 0;
  now = ch[now][s[i] - 'a'];
  if(end[now])return 1;
  }
  return 0;
}

多组数据一定要清空全部数组。
code

#include<bits/stdc++.h>
using namespace std;

int N,tot;
int ch[1000005][30],nxt[1000005],endd[1000005],cnt[155];
struct str{
    char a[75];
}inn[155];
char in[1000005];
struct Ans{
    int num,id;
}ans[155];
inline bool cmp(Ans a,Ans b){
    if(a.num == b.num)return a.id < b.id;
    return a.num > b.num;
}

inline void build(char* s,int id){
    int len = strlen(s);int now = 0;
    for(int i = 0;i < len;++i){
        int c = s[i] - 'a';
        if(!ch[now][c])ch[now][c] = ++tot;
        now = ch[now][c];
    }
    endd[now] = id;
}

inline void get_nxt(){
    queue<int> q;while(q.size())q.pop();
    for(int i = 0;i < 26;++i)if(ch[0][i])q.push(ch[0][i]);
    int now = 0;
    while(q.size()){
        now = q.front();q.pop();
        for(int i = 0;i < 26;++i){
            if(!ch[now][i])ch[now][i] = ch[nxt[now]][i];
            else nxt[ch[now][i]] = ch[nxt[now]][i],q.push(ch[now][i]);
        }
    }
}

inline void ask(char* s){
    int len = strlen(s),now = 0;
    for(int i = 0;i < len;++i){
        int c = s[i] - 'a';
        now = ch[now][c];
        for(int t = now;t;t = nxt[t])++ans[endd[t]].num;
    }
    sort(ans + 1,ans + 155,cmp);
    int num = ans[1].num;
    printf("%d\n",num);
    for(int i = 1;i <= 150&&ans[i].num == num;++i)printf("%s\n",inn[ans[i].id].a);
}

int main(){
    freopen("3796-1.in","r",stdin);
    scanf("%d",&N);
    while(N){
        tot = 0;
        for(int i = 1;i <= N;++i){
            scanf("%s",inn[i].a);
            ans[i].id = i,ans[i].num = 0;
            build(inn[i].a,i);
        }
        get_nxt();
    //  cout<<"                                             over"<<endl;
        scanf("%s",in);
        ask(in);
        memset(ch,0,sizeof ch);
        memset(nxt,0,sizeof nxt);
        memset(endd,0,sizeof endd);
        scanf("%d",&N);
    }
    return 0;
}

相关文章

  • LUOGU3976 AC自动机

    LUOGU3808LUOGU3976Description有个由小写字母组成的模式串以及一个文本串。每个模式串可能...

  • AC自动机 专题整理

    AC自动机学习记录 参考资料 字典树(讲解+模版)AC自动机算法AC自动机算法详解hdu 2222 ac自动机入门...

  • 自动AC机?不,是AC自动机

    今天我们来介绍一点进阶的知识——AC自动机。 AC自动机是啥 AC自动机是什么呢?是不是用了这个算法,不管什么题目...

  • 【AC自动机】AC自动机可以帮你自动AC吗

    参考博文:AC自动机算法详解 (转载) (原文作者:DarkRaven,原文的链接失效了)图片来源:AC自动机算...

  • AC自动机-去除敏感字符

    AC自动机 AC自动机:Aho-Corasick automation,该算法在1975年产生于贝尔实验室,是著名...

  • lucene中文分词

    IK中文分词 DoubleArrayTrie的AC自动机

  • 字符串算法小结

    hash kmp和ac自动机 后缀数组,后缀自动机,后缀树 扩展kmp manacher算法 回文自动机 可删改的...

  • AC 自动机

    AC自动机 AC自动机是一个经典的多模式串匹配算法,它可以实现对主串的一次扫描来匹配多个模式串的功能。实现AC自动...

  • 回文树(附模板题URAL-1960)

    (最好事先学习过kmp,Trie,AC自动机)回文树,有效解决各类回文问题的超级666的树形结构 集AC自动机的f...

  • AC自动机_模板

    AC自动机: 求多个字符串是否在主串中出现过。可依据情况分别求出出现次数,出现位置等。 AC自动机入门Keywor...

网友评论

      本文标题:LUOGU3976 AC自动机

      本文链接:https://www.haomeiwen.com/subject/zwrbeqtx.html