zoukankan      html  css  js  c++  java
  • 洛谷-P5357-【模板】AC自动机(二次加强版)

    题目传送门

    -------------------------------------- 过年在家无聊补一下这周做的几道AC自动机的模板题

    sol:AC自动机,还是要解决跳fail边产生的重复访问,但是这次用last边已经不行了,只能拿76分。我们把跳fail边的过程放到串扫描完之后一次性进行。

    • AC自动机
      #include <bits/stdc++.h>
      using namespace std;
      typedef long long LL;
      typedef pair<int, int> PII;
      const int MAXN = 200010;
      struct Trie {
          int son[MAXN][26], fail[MAXN];
          int que[MAXN]; int head, tail;
          int cnt[MAXN]; int tot, root;
          int add_node() {
              memset(son[tot], -1, sizeof(son[tot]));
              cnt[tot] = 0;
              return tot ++;
          }
          void init() {
              head = tail = 0;
              tot = 0;
              root = add_node();
          }
          int insert(char* s) {
              int p = root;
              for (int i = 0; s[i]; i++) {
                  int index = s[i] - 'a';
                  if (son[p][index] == -1)
                      son[p][index] = add_node();
                  p = son[p][index];
              }
              return p;
          }
          void build() {
              fail[root] = root;
              for (int i = 0; i < 26; i++) {
                  if (son[root][i] == -1) son[root][i] = root;
                  else {
                      fail[son[root][i]] = root;
                      que[++ tail] = son[root][i];
                  }
              }
              while (head != tail) {
                  int p = que[++ head];
                  for (int i = 0; i < 26; i++) {
                      if (son[p][i] == -1) son[p][i] = son[fail[p]][i];
                      else {
                          fail[son[p][i]] = son[fail[p]][i];
                          que[++ tail] = son[p][i];
                      }
                  }
              }
          }
          void slove(char* s) {
              int p = root;
              for (int i = 0; s[i]; i++) {
                  int index = s[i] - 'a';
                  p = son[p][index];
                  cnt[p] ++;
              }
              for (int i = tail; i >= 1; i--) {
                  int p = que[i];
                  cnt[fail[p]] += cnt[p];
              }
          }
      } ac;
      int inde[MAXN]; // 本地运行没什么问题,洛谷叫index就报编译错误
      char s[2000010];
      int main() {
          int n; ac.init();
          scanf("%d", &n);
          for (int i = 1; i <= n; i++) {
              scanf("%s", s);
              inde[i] = ac.insert(s);
          }
          ac.build();
          scanf("%s", s); ac.slove(s);
          for (int i = 1; i <= n; i++)
              printf("%d
      ", ac.cnt[inde[i]]);
          return 0;
      }

      经过不断地40分、60分、76分,终于搞定了。为了在最后跳fail边的时候保证深度越高的节点越先跳采用了手写队列保留bfs时候的层次关系。网上看到别人的代码据说是用拓扑的,没细看。不过感觉这里的队列就是一个对深度的拓扑排序了。

  • 相关阅读:
    python 玩转列表list
    Python入门之_水仙花数
    自兴人工智能 字符串
    自兴人工智能 元组
    自兴人工智能 列表
    自兴人工智能 python特点了解
    python走迷宫
    (自兴人工智能) python 元组
    (自兴人工智能) 玩转 python 字符串
    (自兴人工智能)Python 列表(List)的灵活使用
  • 原文地址:https://www.cnblogs.com/Angel-Demon/p/12233327.html
Copyright © 2011-2022 走看看