AC自动机的一些处理方法

一些经典的问题:
  1. 求各个模式串在文本串中出现了几次:

    方法: 在AC自动机上先跑一边文本串,记录一下每个点被经过的次数,那么单词被经过的次数就是他的结尾在fail树中的子树的权值和

  2. 找是否有一个匹配不上匹配串的环:

    方法: 把所有能匹配上匹配串的节点匹配记录下来,dfs从跟开始走所有我可以走的点,如果我走到了一个之前走过的点就说明出环了

    实现: 一边调用fail一边更新当前点是否能走,因为fail记录的是前缀等于后缀,后缀深度一定比前缀大,所以fail一定在之前就走过了

  3. \(n\)个串总共出现\(m\)次的最短长度

    方法: 求两两单词结尾之间的最短距离,初始矩阵\(a_{i,j}\)表示结尾\(i\)和结尾\(j\)之间不经过其他结尾的最短距离,矩阵快速幂\(m-1\)

    更新成\(a_{i,j}\)表示结尾\(i\)到结尾\(j\)之间经过其他\(m-2\)个结尾的最小距离,现在总共经过了\(m\)个单词结尾,再加上第一个单词的长度,就是最短长度,一共\(nm\)种情况取最小的一种

  4. 每次删掉文本串中的最早出现的模式串,剩下的字符继续拼在一起

    方法: 跑AC自动机,模拟栈,发现匹配到一个单词,把属于这个单词的字符全部弹出,继续从之前匹配的位置继续往下找

注意问题:
  1. 在fail树上拓排的时候在更新fail指针的时候进行,如:
      fail[trie[root][i]] = trie[fail[root]][i];
      du[trie[fail[root]][i]] ++;
  1. 看当前字符是否能匹配上匹配串是在调用fail的时候进行,如:
      trie[root][i] = trie[fail[root]][i];
      vis[trie[root][i]] |= vis[trie[fail[root]][i]];
posted @ 2020-11-28 09:14  小又又yyyy  阅读(154)  评论(0编辑  收藏  举报