码迷,mamicode.com
首页 > 其他好文 > 详细

【专题】字符串专题小结(AC自动机 + 后缀自动机)

时间:2018-07-28 23:27:19      阅读:243      评论:0      收藏:0      [点我收藏+]

标签:bsp   view   spl   选择   专题   hide   一段   前缀   ide   

AC自动机相关:

 

后缀自动机相关:

求一个串的不重复子串个数。

这是后缀自动机上的一个经典问题,很多时候它都会作为解决一个问题的子问题。事实上这个问题很容易想到,每一个子串都别表现在了自动机上的一个节点,所有相同的子串只会被表现一次,重复的将算在$right$集合中了。每个节点包含的不重复子串个数就是$max_{i} - min_{i} + 1$连续的一段,把所有节点包含的不重复子串数量相加就行了。

$ans = \sum_{i = 1}^{tot} dep_{i} - dep_{fa_{i}}$。

将所有子串按照字典序排序:

由于字典序是比较前缀的,通常情况我们把反串建出后缀自动机,那一个节点上表示的子串都有同样的后缀,对应了原串的前缀,那我们只要对反串进行后缀意义上的排序就可以了。很显然,一个节点中表示的所有子串一定在后缀字典序中是连续的。于是,我们对于$parent$树上每一个节点$x$,假设$y = fa_{x}$,$x$中最短的子串比$y$中最长的子串多的那个字符$a$一定会在$y$中最长串的前一格,那我们就定$son_{y,a} = x$。显然,$son$表示的就是一棵树,这棵树的$Dfs$序就是我们要求的对于每个节点而言的后缀字典序,因为我们在对它进行$Dfs$时会优先选择下一个字符较小的串。

以下给出具体建树的实现:

技术分享图片
void Dfs(int t) {
  id[++tp] = t;
  for (int i = 0; i < 26; ++i) {
    if (son[t][i]) Dfs(son[t][i]);
  }
}

void Build() {
  for (int i = 1; i <= tot; ++i) ++bit[dep[i]];
  for (int i = 1; i <= tot; ++i) bit[i] += bit[i - 1];
  for (int i = tot; i >= 1; --i) id[bit[dep[i]]--] = i;
  for (int i = tot; i >= 1; --i) {
    int x = id[i];
    son[fa[x]][s[ed[x] - dep[fa[x]]] - a] = x;
  }
  Dfs(1);
}
View Code

(注:其中$ed_{i}$表示节点$i$表示的子串末尾字符的位置)

求出字典序第$k$小子串:

此处分两种,一种是算重复子串,一种是不算重复子串,本质上没有区别,如果算重复子串只要对每个节点多乘上$right$集合大小就可以了。

有了上一个模型,我们只要在$Dfs$后的序列上二分就可以了,维护一个前缀的$sum_{i}$表示前$i$个节点表示的子串有多少个,二分可以找到第$k$小子串所在的节点,就能知道是那个子串了。以上是不计重复子串的,如果算上重复子串,由于每个节点上的$right$集合大小是一样的,所以在计算子串个数时乘上$right$集合大小即可,另一个问题,如果不算重复子串,

【专题】字符串专题小结(AC自动机 + 后缀自动机)

标签:bsp   view   spl   选择   专题   hide   一段   前缀   ide   

原文地址:https://www.cnblogs.com/Dance-Of-Faith/p/9383750.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!