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{len}_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

posted @ 2022-02-01 09:48  gzezFISHER  阅读(21)  评论(0编辑  收藏  举报