CF587F Duff is Mad

更好的阅读体验

题意

给定 \(n\) 个字符串 \(S_{1...n}\).
定义 \(\text{occur}(t, s)\) 为 字符串 \(t\) 在字符串 \(s\) 中的出现次数. 有 \(q\) 次询问,每次给出 \(l\),\(r\) 和 \(k\),输出 \(\sum\limits_{l\le i\le r}\text{occur}(s_i, s_k)\).

\(n,k,\sum |s_i|\le 10^5\)

题解

我们对所有串建立fail树

令 \(p_{i,j}\) 表示串 \(s_i\) 的前 \(j\) 个字符在AC自动机上对应点的编号,\(end_{i}\) 表示串 \(s_i\) 在AC自动机上对应点的编号

\[\sum_{l\le i\le r}\text{occur}(s_i, s_k)=\sum_{l\le i\le r}\sum_{1\le j\le \text{size}_k}\text{isanc}(end_{i}, p_{k, j}) \]

其中 \(\text{isanc}(x, y)\) 表示在fail树上 \(x\) 是否为 \(y\) 的祖先

看到 \(\sum |s_i|\le 10^5\) 这条限制,容易想到对于 \(|s_k|\) 根号分治

令 \(M=\sum |s_i|\)

  • \(|s_k|<=T\)
    容易得到一种做法,\(\forall l\le i\le r\),对所有以 \(end_i\) 为根的子树的所有点加1,然后查询所有 \(p_{k,i}\) 点上的值之和
    把每个询问差分为成 \([1, l-1]\) 和 \([1, r]\) 两个区间,然后离线下来按右端点排序,维护区间修改单点查询
    树状数组可以做到 \(\mathcal{O}(qT\log M+n\log M)\),当然更快的做法是分块的 \(\mathcal{O}(qT+n\sqrt{M})\)
  • \(|s_k|>T\)
    满足这个条件的 \(k\) 数量是 \(\mathcal{O}(\frac{M}{T})\) 级别的,因此我们考虑对所有的 \(k\) 预处理
    考虑另一种做法,把所有 \(p_{k,i}\) 标上1,然后查询 \(\forall l\le i\le r\),\(end_i\) 子树和之和
    预处理时我们对 \(end_i\) 的子树和做前缀和,询问的差分即可
    \(\mathcal{O}(q+\frac{M}{T}\times n)\)

选择一个合适的 \(T\),我们视 \(n\),\(M\) 和 \(q\) 为同阶,\(T\) 取 \(\sqrt{M}\) 即可
复杂度可以简单地认为是 \(\mathcal{O}(n\sqrt{M})\)

代码 codeforces submission 144319232

上一篇:浅谈积和类问题


下一篇:洛谷 P4548 - [CTSC2006]歌唱王国(概率生成函数)