P3735 [HAOI2017] 字符串 题解

· · 题解

首黑祭。
考察:AC 自动机,树状数组,线段树,差分,常数优化。
题目简述:
小 Z 收到了一个字符串 s 及一坨字符串 \{p_n\},求每个 p_is 中出现的次数。

字符串 t 在字符串 s 中出现的次数定义是 s 中的不同的子串 s' 满足 s'\approx t 的个数。

$s\approx t$ 指: 1. $|s|=|t|
  1. \forall i,j\in[1,|s|]\cap\mathbb Z,s_i\ne t_i,s_j\ne t_j,|i-j|<k

数据范围:

这就出现了类多模字符串匹配,掏出我们的 AC 自动机。\forall i\in[1,n]\cap\mathbb Z,将 p_ip_i 的反串(包括 ss 的反串,但为了卡常加入它们时可以不新建节点)扔进 AC 自动机里,然后算 lst(其实就是 fail,不过我不习惯用它,目的是为了避免与某些稀奇古怪的函数冲突的可能性)指针,建立 lst 树。
如果 p_is 前缀恰好匹配到了第 j 位,那么后缀至少要匹配到 j+k+1 位。
注意到恰好不好计算,我们就采用差分思想。
p_i 的第 j 位在 AC 自动机上的节点是 u,反串 j+k+1 位是 v,在 s 上与之对应的左右端点分别是 x,y,那么需要满足 xu 的子树中且 yv 的子树中。
那么我们遍历整棵树,将询问和修改挂到树上做就可以了,具体实现见代码。

代码