26-02

CF

CF666E

依旧串串。最大值感觉很难做哎?能不能根号分治一下。依旧不会。是不是可以对于模式串建出 GSAM,然后依旧扫描线。把询问挂到 \(p_r\) 上去,扫描线的过程中就用 \(s\) 在 GSAM 上匹配,然后对于每种询问就不断在 \(\text{link}\) 树上往上倍增跳到长度合法的状态。然后就转化成了对于每一个状态,需要求出 \([l, r]\) 区间内的最大的 \(\text{endpos}\) 集合。发现可以用权值线段树+可持久化线段树合并维护。

CF1037H

考虑询问如果是全局的该怎么做。对 \(s\) 建出 SAM,然后把每次询问的 \(x\) 丢到 SAM 上去匹配。贪心的考虑,如果中间失配,就选取最小的可走的转移走,然后输出。否则,在走完之后取最小转移边,然后输出。

如果询问不是全局,可能就有一些套路的 \(\text{link}\) 树上的内容了。考虑在非全局的询问下,如果走到一个位置失配了,那么该怎么办。首先肯定是用可持久化线段树合并维护 \(\text{endpos}\) 的位置,然后如果走到的位置没有在给定区间内的 \(\text{endpos}\),是不是就可以直接弃掉了?似乎很是的样子。因为这么短的没有,长的肯定更加没有了。

全局的做法有点假了,感觉还得在 SAM 上做一遍 DAG 上的 DP 预处理一下?用 bitset 维护?似乎不用了,在转移时用线段树查询一下就 ok 了。

问题很大,因为求的是严格大于的字典序。这倒也无关紧要,特判一下就行了?总的来说,答案不会超过 \(2\times 10^5+q\)

CF2193H

考虑简化问题,把所有的点权改成 \(0\)\(1\)。然后如果删掉一个点 \(0\),将不会对与其相连的点有影响;如果删掉一个点 \(1\),则与其相连的点的 \(S\) 都会取反。

如果一个点在初始的情况下不满足条件,即不能被删除,那么后续必然会对与其相邻的权值为 \(1\) 的节点操作奇数次,再将其删除。否则,该节点可以在操作了偶数次 \(1\) 或任意次 \(0\) 之后删除。

删除的顺序不好考量,但是可以确定的是,最后剩下来的孤点权值都是为 \(1\) 的。

换句话说,在重构了点权之后,\(S\operatorname{xor} a_i=1\) 的点都是能被删掉的。同时,可以发现,初始状态下能被删的 \(0\) 优先删了一定是最优的。然后发现接下来会出现森林,若每一个森林里都有一个能删的 \(1\) 就一定可以删完。这个结论是错的,因为有 \(0\) 的存在,但是我们可以不考虑 \(0\),将森林进一步细分。为什么一个连通块里有一个能被删的 \(1\) 就能删完呢?因为删掉这个 \(1\) 后旁边的不能删的点的状态就会取反,变成能删了(此时的连通块是去除所有\(0\) 后的连通块)。然后对于每一个初始情况下不能被删掉的 \(0\),若在删除过程中有一刻变成了能删掉,直接删就行了。

接下来考虑如果一个连通块里有多个可以被删的 \(1\) 怎么办。手玩发现,如果一个连通块里有奇数个可被删的 \(1\) 就能被删完,否则不行。

删的过程 \(\text{bfs}\) 实现即可。

完了,删除的过程假了。不能用朴素的搜索实现?

结论错了,是连通块大小为奇数就一定能删干净。优先删叶子节点竟然是对的???

CF235C

考虑对 \(S\) 建出 SAM,然后每次将询问的 \(x_i\) 复制两份少一个字符,丢到 SAM 上去匹配。需要注意的是每次的匹配到的长度都只能是 \(|x_i|\)。所以我们只需要对 \(S\) 的 SAM 求一下 \(\text{endpos}\) 集合的大小就行了。

CF696D

感觉很是 \(\text{ACAM}\) 上的 \(\text{dp}\) 了。但是,谁家好人 \(l\le 10^{14}\) 啊!

tag 很有道理,不会是矩阵加速优化吧。先考虑朴素的 dp。设 \(f_{u, i}\) 表示走到 \(\text{ACAM}\) 上的点 \(u\) 且当前已经情话字符串长度为 \(i\) 的最大答案。转移就是刷表,\(w_u\) 可以在建 \(\text{ACAM}\) 时顺便处理出来:

\[f_{u,i}\leftarrow f_{fa_u, i-1}+w_u \]

数据范围让人联想到邻接矩阵快速幂啊,而且这不正是经过 \(l\) 条边的最大值吗?然后把点权转成边权不就搞定了吗?easy……

CF587F

建出 \(\text{ACAM}\),则对于每一个询问就相当于,在 \(\text{fail}\) 树种每一个 \(s_i\) 的终止节点的的子树里 \(+1\),然后查 \(s_k\) 的所有节点。

发现直接做很难做,同时数据范围放了根号做法,考虑根号分治。

\(|s_k|\ge B\),则这样的 \(s_k\) 只有 \(O(\frac{\sum|s_i|}{B})\) 个,可以直接对于每一个 \(s_k\) 线性暴力地去做。

否则,直接用树状数组维护子树加,然后暴力在 \(\text{fail}\) 树上查链的贡献。

\(m=\sum |s_i|\),平衡一下,当 \(B\)\(\frac{m}{\sqrt{q\log m}}\) 时最优。总时间复杂度是 \(O(n\log m+ q\log q+m\sqrt{q\log m})\)

LG

P5218

由裴蜀定理扩展形式可以直接将这题转化为求若干数的 \(\gcd\)\(1\) 的情况。即:

\[\sum_{a=1}^{n}\sum_{b=1}^{n}\cdots\sum_{x=1}^{n}[\gcd(a, b, \cdots, x)=1] \]

莫反:

\[\sum_{a=1}^{n}\sum_{b=1}^{n}\cdots\sum_{x=1}^{n}\sum_{d\mid \gcd(a, b, \cdots, x)}\mu(d) \]

改变枚举顺序得:

\[\sum_{d=1}^{n}\mu(d)(2^{\lfloor\frac{n}{d}\rfloor}-1) \]

杜教筛+整除分块即可。

P14400

推式子推傻了后可以来做一做清新分块。

观察到每一个数只可能被前面的比起小的数替换,考察这个东西的更具体的性质。它只会有可能被 \([S_i, j]\)\(j\) 为其下标)的比其小的最大值替换掉。不满足区间可合并性,考虑分块。

对于同一个块内,因为我们只需要关注结果,不需要关注过程,所以想办法搞一搞。类似由乃的 OJ 那题,对于每一个块预处理出每一个数在经过这个块后会变成什么数。发现每次变化都会在前缀最大值的地方变化。所以我们只需要找到每块最后一个前缀最大值,然后判断其是否比给定的数大。散块直接暴力模拟就行了。

现在的问题在于如何支持修改。原来 \(q\) 那么小啊,那就可以 \(q\sqrt{n}\log n\) 了。考虑到整块只需要考虑块内最大值,而散块则需要暴力模拟一下。思考这个模拟过程,发现只有比当前数值 \(x\) 要大且处于给定区间的数才能有贡献,且每次必然是最前的数有贡献。所以考虑对每一个块都开一个权值线段树,但是这怎么处理末尾散块的情况。

突然发现既然每次进去都会变成最大值,那么散块也直接查询最大值就行了。问题此时转变成怎么在修改之后处理出散块中的数的值。考虑重构,但是我不会啊。有一个暴力模拟的方法,对于每一次有数经过这个块就将其记录下来,然后用小根堆存储。观察操作的本质会令每一个位置被最小的数占据,所以在重构时用小根堆模拟这个过程。每遇到一个比堆顶大的数就将那一个数压入堆,并弹出堆顶,这样就重构对了。

时间复杂度是严格的 \(O(q\sqrt{n}\log n)\)

P6055

一顿捣鼓之后推出这个东西:

\[n^2\sum_{d=1}^{n}\mu(d)\lfloor\frac{n}{d}\rfloor^2 \]

杜教筛启动。

艹,式子推错了啊。

观察到 \(j\) 等价于是 \(jp\)\(jq\) 的最大公因数,所以原式可以改写成:

\[\sum_{i=1}^{n}\sum_{p=1}^{n}\sum_{q=1}^{n}[\gcd(i, \gcd(p, q))=1] \]

于是乎:

\[\sum_{i=1}^{n}\sum_{q=1}^{n}\sum_{p=1}^{n}[\gcd(i, p, q)=1] \]

依旧莫反:

\[\sum_{i=1}^{n}\sum_{q=1}^{n}\sum_{p=1}^{n}\sum_{d\mid \gcd(i, p, q)}\mu(d) \]

改变枚举顺序:

\[\sum_{d=1}^{n}\sum_{i=1}^{\lfloor n/d\rfloor}\sum_{p=1}^{\lfloor n/d\rfloor}\sum_{q=1}^{\lfloor n/d\rfloor}\mu(d) \]

整除分块加杜教筛就行了:

\[\sum_{d=1}^{n}\mu(d)\lfloor\frac{n}{d}\rfloor^3 \]

P2257

形式化题意:

\[\sum_{i=1}^{n}\sum_{j=1}^{m}[\varphi(\gcd(i, j))=\gcd(i,j)-1] \]

枚举最大公因数然后莫反得到:

\[\sum_{d=1}^{n}[\varphi(d)=d-1]\sum_{k=1}^{\lfloor n/d\rfloor}\mu(k)\lfloor\frac{n}{dk}\rfloor\lfloor\frac{m}{dk}\rfloor \]

\(T=dk\),就有:

\[\sum_{T=1}^{n}\lfloor\frac{n}{T}\rfloor\lfloor\frac{m}{T}\rfloor\sum_{k\mid T}\mu(k)[k\in \text{prime}] \]

容易发现后半部分是可以预处理的,于是整除分块做完了。

P3704

随便乱推套点莫反得到(钦定 \(n<m\)):

\[\prod_{d=1}^{n}f_d^{\sum_{k}^{\lfloor n/d\rfloor}\mu(k)\lfloor\frac{n}{kd}\rfloor\lfloor\frac{m}{kd}\rfloor} \]

套路地整个 \(T=kd\) 出来得:

\[\prod_{T=1}^{n}\prod_{d\mid T}f_d^{\lfloor\frac{n}{T}\rfloor\lfloor\frac{m}{T}\rfloor\mu(\frac{T}{d})} \]

可以把 \(\mu\)\(f\) 丢到一起去预处理一下,然后剩下的直接整除分块就行了。

P1447

推式子,看着就很仪仗队。

观察结论,发现每个点的贡献为横纵坐标最大公因数乘二减一(不妨钦定 \(n<m\)):

\[\sum_{i=1}^{n}\sum_{j=1}^{m}\left(2\gcd(i, j)-1\right) \]

上个欧拉反演:

\[2\sum_{i=1}^{n}\sum_{j=1}^{m}\sum_{d}[d\mid i][d\mid j]\varphi(d)-nm \]

枚举 \(d\) 得:

\[2\sum_{d=1}^{n}\sum_{i=1}^{\lfloor n/d\rfloor}\sum_{j=1}^{\lfloor m/d\rfloor}\varphi(d)-nm \]

直接套整除分块就行了:

\[2\sum_{d=1}^{n}\lfloor \frac{n}{d}\rfloor\lfloor \frac{m}{d}\rfloor\varphi(d)-nm \]

跑得还没线性做法快

P3735

考虑刻画两个相等的串,即为拥有公共前后缀,然后非最长公共前后缀的长度不超过 \(k\)

想到建一个 SAM。

考虑如果知道了一个模式串的每一个后缀在文本串中的 \(\text{endpos}\) 那会不会好做一点。这样就只需要判断前缀了。前缀的判断应该是可以直接丢到 SAM 上跑出来的。

对于模式串 \(s[1:i]\)\(s[i+1:n]\),若 \(s[i+1:n]\) 已经跑出来了在文本串 \(t\) 中的 \(\text{endpos}\)。考虑查询有多少个能与其相匹配的前缀。这些前缀需要满足的条件就是与该后缀的长度之差 \(\le k\)
感觉这样很难做。

注意到可以强行将失配的部分补成 \(|k|\) 的长度。于是可以提前在 \(s\) 中将要匹配的区间都预处理出来,在 SAM 里进行一些标记。套路地,在询问的 \(t_i\) 中也这样枚举划分点。

改成 ACAM,正串反串都建一个,然后把每一个划分点的节点都标记并建立映射,在 \(\text{fail}\) 树上 BIT 维护扫描线就行了。有重,所以需要容斥,用长度为 \(k\) 的减去长度为 \(k-1\) 的就对了。

调不出来,咕着。

P1829

形式化题意:

\[\sum_{i=1}^{n}\sum_{j=1}^{m}\text{lcm}(i, j) \]

经典转化:

\[\sum_{i=1}^{n}\sum_{j=1}^{m}\frac{ij}{\gcd(i, j)} \]

考虑改变一下顺序,先枚举 \(\gcd(i, j)\),得到:

\[\sum_{d}\sum_{i=1}^{\lfloor n/d\rfloor}\sum_{j=1}^{\lfloor m/d\rfloor} [\gcd(i, j)=1]\frac{ij}{d} \]

尝试对其应用莫比乌斯反演:

\[\sum_{d}\sum_{i=1}^{\lfloor n/d\rfloor}\sum_{j=1}^{\lfloor m/d\rfloor}(\sum_{k}[k\mid i][k\mid j]\mu(k))ijd \]

改一下求和顺序得到:

\[\sum_{d}d\sum_{k}\mu(k)(\sum_{i=1}^{\lfloor n/d\rfloor}\sum_{j=1}^{\lfloor m/d\rfloor}i[k\mid i]j[k\mid j]) \]

观察形如如下式子的贡献:

\[\sum_{i=1}^{\lfloor n/d\rfloor}i[k\mid i]=k\sum_{i=1}^{\lfloor\lfloor n/d\rfloor/k\rfloor}i=kG(\lfloor\frac{n}{kd}\rfloor) \]

\(G\) 函数便是等差数列求和,所以原式变成了:

\[\sum_{d}d\sum_{k}\mu(k)k^2G(\lfloor\frac{n}{kd}\rfloor)G(\lfloor\frac{m}{kd}\rfloor) \]

枚举乘积 \(kd=\ell\) 并转化求和顺序得:

\[\sum_{\ell}(\sum_{k\mid \ell}\mu(k)k\ell)G(\lfloor\frac{n}{\ell}\rfloor)G(\lfloor\frac{m}{\ell}\rfloor) \]

设函数:

\[F(x)=\sum_{k\mid x}\mu(k)kx \]

容易观察到 \(F\) 是一个积性函数,所以可以线性筛预处理,然后再用整除分块即可。

P2522

形式化题意为:

\[\sum_{x=a}^{b}\sum_{y=c}^{d}[\gcd(x, y)=k] \]

先对原式进行容斥,然后每一部分都形如:

\[\sum_{i=1}^{n}\sum_{j=1}^{m}[\gcd(i, j)=k] \]

显然 \(i\)\(j\) 都必须是 \(k\) 的倍数,不能包含其它的公因数,所以有:

\[\sum_{i=1}^{\lfloor\frac{n}{k}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{k}\rfloor}[\gcd(i, j)=1] \]

尝试对其应用莫比乌斯反演,得到:

\[\sum_{i=1}^{\lfloor\frac{n}{k}\rfloor}\sum_{j=1}^{\lfloor\frac{m}{k}\rfloor}\sum_d[d\mid i][d\mid j]\mu(d) \]

交换求和顺序:

\[\sum_d\mu(d)(\sum_{i=1}^{\lfloor\frac{n}{k}\rfloor}[d\mid i])(\sum_{j=1}^{\lfloor\frac{m}{k}\rfloor}[d\mid j]) \]

后半部分很典,可以整除分块处理,即:

\[\sum_d\mu(d)\lfloor\frac{\lfloor\frac{n}{k}\rfloor}{d}\rfloor\lfloor\frac{\lfloor\frac{m}{k}\rfloor}{d}\rfloor \]

于是线性筛预处理 \(\mu(d)\) 然后整除分块处理就行了。

时间复杂度为 \(O(V+n\sqrt{V})\),其中 \(V\) 是值域。

P2260

服了,纯推式子的题目。

\[\begin{aligned} &\ \ \ \ \ \ \sum_{i=1}^{n}\sum_{j=1}^{m}(n\bmod i)\times (m\bmod i)\times [i\neq j]\\ &=\sum_{i=1}^n\sum_{j=1}^m(n-i\times \lfloor\frac{n}{i}\rfloor)\times (m-j\times \lfloor\frac{m}{j}\rfloor)-\sum_{i=1}^{\min(n, m)}(n-i\times \lfloor\frac{n}{i}\rfloor)\times (m-i\times \lfloor\frac{m}{i}\rfloor)\\ &=n^2m^2-n^2\times \sum_{j=1}^{m}j\times \lfloor\frac{m}{j}\rfloor-m^2\times \sum_{i=1}^{n}i\times \lfloor\frac{n}{i}\rfloor+\sum_{i=1}^{n}i\times \lfloor\frac{n}{i}\rfloor\times \sum_{j=1}^{m}j\times \lfloor\frac{m}{j}\rfloor-\sum_{i=1}^{\min(n, m)}(n\times m-n\times i\times \lfloor\frac{m}{i}\rfloor-m\times i\times \lfloor\frac{n}{i}\rfloor+i^2\times \lfloor\frac{n}{i}\rfloor\times \lfloor\frac{m}{i}\rfloor) \end{aligned} \]

上几个整除分块就行了。

P3935

题目需要求 \([l, r]\) 中每一个数的因数个数之和。

注意 \(f\) 是积性函数,即满足当 \(\gcd(i, j)=1\) 时有 \(f(i \times j)=f(i)\times f(j)\)

屁用没有,考虑转化拆贡献,则原式变成:

\[\sum_{i=1}^r(\lfloor\frac{r}{i}\rfloor-\lfloor\frac{l-1}{i}\rfloor) \]

形如整除分块形式,这就能做了。

P8368

\(T_0,T_1,T_2\) 似乎没什么观察。但注意到从 \(T_3\) 开始后,\(T_i\)\(T_{i-1}\) 必须拥有长度为 \(i-2\) 的公共前后缀。由 \(T_i\)\(T_{i+1}\) 的转变就是删掉第一个字符,然后添加两个字符,这样第二、三个条件就都满足了。

但是感觉很困难啊。考虑能不能 DP。发现答案的下界为 \(\lfloor\frac{n}{2}\rfloor\),因为有显然的倒着构造的方案 \([i, j], [i-1,j-2], [i-2, j-4]\cdots\)

考虑能否从 \([i_1,j_1]\) 回到 \([i_2, j_2]\),满足 \(i_1<i_2,j_1-i_1=j_2-i_2+1\)。如果可以回到,那么答案就有可能更大。相当于长度为 \(i_1-j_1、\) 长度的子串出现了至少两次。所以需要维护一下每种子串的出现次数,这就可以 SAM 维护。对于每一个状态取 \(\text{maxlen}\) 计算答案,最终 \(ans\leftarrow \max\{\text{maxlen}+\lfloor\frac{n-r}{2}\rfloor\}\)

P6816

观察到题目等同于找一个子串,然后每次用子串的一个后缀去覆盖,同时,每次覆盖时子串的非后缀部分为其 \(\text{border}\) 的一部分。倒不一定,因为最后一个覆盖显然有可能会超出范围。

考虑到一个事情,只需要建出 SAM,然后使得 \(\text{endpos}\)\(\text{endpos}\) 之间的长度不超过 \(\text{len}\),那么肯定是一个合法的答案。故对于每一个 SAM 状态,答案一定形如一段以 \(\text{maxlen}\) 开头的区间。然后剩下需要做的便是 check 第一个 \(\text{endpos}\) 前和最后一个 \(\text{endpos}\) 后的子串合不合法。前缀的判断是容易的,只需要在 \(\text{link}\) 树上查询从根到当前状态最前的 \(\text{endpos}\) 的最后位置,如果有交,那么合法。对于后缀的判断能否考虑对反串建 SAM?

似乎是可以的,每次在反串的 SAM 上倍增找到合法的状态,然后按上面的方法进行查询。

接下来考虑如何找字典序最小的子串。考虑在 SAM 上遍历查找的话有没有什么性质,即如果走到一个状态 \(u\) 不合法,那么其转移到的节点是否也就都不合法了。发现这个东西是假的。

停停停,原来是求的最短的 \(s\),然后再字典序最小啊!最短的 \(s\) 是容易的,还是考虑字典序最小有没有什么性质。

原来字典序可以二分+hash?

好难啊,先咕着吧……

P3426

注意到操作等同于每次添加所选子串的一个后缀,且子串长度减掉后缀长度 \(\le |\text{border}|\)。考虑跑一边 KMP 把前缀函数先预处理出来。同时注意到印章穿一定是原串的一个 \(\text{border}\)。ok,先学失配树,再来挑战这题。

又注意到一个东西,每次拼接相当于是把原串的一段 \(\text{border}\) 进行拼接(但事实确是将其重叠然后将剩余部分拼接),所以和 KMP 关系非常大。然后进行一个神秘的 DP,设 \(f_i\) 表示前 \(i\) 位的最短印章,则显然这东西只能等于 \(f_{\text{border}_i}\)\(i\),考虑判断这个东西什么时候选前者。

发现需要存在一个点 \(j\),使得 \(s[1:j]\) 能被 \(f_{\text{border}_i}\) 覆盖且 \(j\ge i-|\text{border}_i|\)。实现是容易的。

P5999

转换题意,相当于求长度为 \(n-2\) 的排列个数,使得 \(\forall i,\{a_i>\max(a_{i-1},a_{i+1})\lor a_i<\min(a_{i-1}, a_{i+1})\}\)

考虑连续段 DP。设 \(f_{i, j}\) 表示插入了前 \(i\) 个数字且当前有 \(j\) 个连续段的答案。转移只可能是合并或新增连续段,然后做完了。

P7967

正难则反,考虑用总数减去能互相吸引的个数,

P9197

显然,如果朴素 dp 需要状压,所以两档部分分都是好拿的。但是!!!数据范围太大了!!!

考虑将 dp 的过程转换为一个从小到大往序列中插入数字的过程。同时,这样可以把绝对值符号给去掉。

已严肃学习连续段 DP。

P5024

写一下朴素的转移式。设 \(f_{u, 1/0}\) 表示以 \(u\) 为根的子树,\(u\) 选/不选的答案。转移如下:

\[f_{u, 1}=\sum_{v\in son_u}\min\{f_{v, 0}, f_{v, 1}\}+a_u \]

\[f_{u, 0}=\sum_{v\in son_u}f_{v, 1} \]

套路地,如果可以用矩阵搞出这个东西,就可以直接用动态 DP 了。改写转移式,设 \(g_{u, 1}\) 表示轻儿子可选可不选且 \(u\) 选的贡献,则第一个转移式简化为(\(f_{v, 0}\) 表示重儿子的贡献):

\[f_{u, 1}=g_{u, 1}+\min\{f_{v, 0}, f_{v, 1}\} \]

第二个转移式就变成了:

\[f_{u, 0}=g_{u, 0}+f_{v, 1} \]

现在开始推矩阵。设转移矩阵为 \(U\)\(v\)\(u\) 的重儿子,定义广义矩阵乘为取 \(\min\),有:

\[U \times \begin{pmatrix} f_{v, 0}\\ f_{v, 1} \end{pmatrix} =\begin{pmatrix} f_{u, 0}\\ f_{u, 1} \end{pmatrix} \]

显然,可以设 \(U\) 为:

\[\begin{pmatrix} a&b\\ c&d\\ \end{pmatrix} \]

则:

\[\begin{pmatrix} a&b\\ c&d\\ \end{pmatrix} \times \begin{pmatrix} f_{v, 0}\\ f_{v, 1} \end{pmatrix} =\begin{pmatrix} f_{u, 0}\\ f_{u, 1} \end{pmatrix} \]

所以:

\[\begin{aligned} \min\{a+f_{v, 0}, b+f_{v, 1}\}=f_{u, 0}\\ \min\{c+f_{v, 0}, d+f_{v, 1}\}=f_{u, 1} \end{aligned} \]

联系转移式得到:\(a=+\infty\)\(b=g_{v, 0}\)\(c=d=g_{v, 1}\)。所以 \(U\) 为:

\[\begin{pmatrix} +\infty&g_{v, 0}\\ g_{v, 1}&g_{v, 1}\\ \end{pmatrix} \]

剩下的东西就很典了。拿树剖和线段树维护这些转移矩阵和初始矩阵,然后每次查询就改一下那两个点的矩阵,再算答案,然后再改回来。

P4094

转换一下题意,每次询问相当于求以 \(c\) 开头的长度不超过 \(d-c+1\) 的串串中在 \([a, b]\) 出现的最长串串。所以考虑离线做一下,把询问都挂到 \(c\) 上去,然后倒着枚举 \(c\)。这样我还是不会做啊!

考虑一个事情,那就是如果把弄一个原串的反串出来,那么每次的询问就相当于是求 \([a, b]\) 这段区间中的状态满足 \(\text{endpos}=c\) 的最长子串。然后你考虑从前往后枚举 \(c\),再对于询问去 check 最长的 \(\text{endpos}\) 序列,但这个东西很不好搞,也不能分治的样子。

观察到答案是有单调性的,具体地说,如果长度为 \(x\)\(\text{endpos}\) 状态不符合答案,那么 \(\ge x\) 就更不会有贡献了。

在 SAM 考虑很难受,直接把询问丢到 \(\text{link}\) 树上观察。发现,求的东西是以 \(c\) 结尾的一系列状态在 \([a, b]\) 区间中的最大值。这样似乎就比较好做了。套路地,用线段树合并维护 \(\text{endpos}\) 的位置,然后只需要找到每一个状态对应的终止字符就行了。最后基排然后拓扑时顺便线段树合并上去。询问就是线段树上二分然后取 \(\max\)。但这样复杂度会爆炸!

考虑对于每一次询问都进行二分答案。然后 check 是否存在一个长度为 \(\text{mid}\) 的子串在 \([a, b]\) 区间内。但是我不会 check?

噢噢噢噢哦哦哦,原来可以在 \(\text{link}\) 树上倍增找第一个满足的状态,搞懂了。所以可以直接用可持久化线段树合并维护 \(\text{endpos}\) 集合,然后二分答案的时候只需要从 \(s[1:c]\) 倍增找到 \(s[c - mid+1:c]\) 所在的状态,然后查询权值线段树以 check 就行了。具体的,就是查询 \([b+mid-1, a]\) 中有没有 \(\text{endpos}\)

时间复杂度是双老哥的。

P4770

注意到子串问题,考虑建 SAM。同时因为涉及到多次询问,令人想到 GSAM。

考虑一次询问的在 GSAM 上的本质是什么。可以在 GSAM 上把文本串的 \(\text{endpos}\) 集合都标记出来,然后如果这些 \(\text{endpos}\) 集合与查询的 \([l, r]\) 区间有交集且该状态是在此次询问中遇到过的状态,那么该状态肯定没有贡献了;否则,该状态对于此次询问会有 \(\text{len}_p-\text{len}_{\text{link}_p}\) 的贡献。

发现每次询问都这样判断是困难的,而 \(\text{endpos}\) 集合的维护只能通过 bitset 或线段树合并来维护,而 bitset 显然被舍弃了。但线段树合并是不能在线的,所以考虑把询问拆成各个状态对答案的总贡献,然后离线下来通过线段树合并计算即可。

感觉还不算很难?时间复杂度为 \(O((q+|S|+\sum|T|)\log (|S|+\sum|T|))\)

代码实现稍有些复杂,因为 GSAM 的形态可能因为克隆节点而变换,所以需要等 GSAM 完全建完之后再对每一个串串进行 GSAM 上匹配,然后将询问挂到匹配到的状态上。最后再线段树合并就行了。

不知道是代码写错了,还是思路假了。

考虑一个部分分,当 \(l=1,r=|S|\) 时,如何计算答案。

可以对于 \(S\)\(T\) 都先建出 SAM,然后直接在 \(T\) 上匹配算答案。

然后考虑 \(l\)\(r\) 随机时只需要判断匹配到的一个状态是否出现在 \([l, r]\) 中,以及出现的最长子串的长度。可以用可持久化线段树合并维护 \(\text{endpos}\) 实现。每次对答案的贡献的计算是容易的。

P11287

比较显然的,可以先把所有的关键点删掉,然后把连通块缩成一个点,其点权为连通块里的点的点权和。每次查询就等同于查询与关键点相连的连通块的权值之和就行了。

问题在于如果每次都枚举与关键点相连的点会炸,因为这样不能保证复杂度,可以被卡到 \(O(qn)\)。如何优化?

根号分治,钦定阈值 \(B\)

  • 若关键点 \(u\) 的度数 \(< B\),则直接暴力枚举查询答案。
  • 若关键点 \(u\) 的度数 \(\ge B\),则说明这样的点一定不超过 \(\frac{m}{B}\) 个,所以可以对于每一次修改都预处理出这些点的答案。

总时间复杂度为 \(O(q(B+\frac{m}{B}))\),当 \(B=\sqrt{m}\) 时有最优复杂度 \(O(q\sqrt{m})\)

P3645

为什么降绿了啊???

考虑如果能够图论建模出来就可以 \(O(n)\) 求出答案,只需要 \(\text{bfs}\) 即可。同时注意到连边时复杂度很高,所以可以对于每一个“大楼”都建一个虚点,最后答案再除以二就行了。

图论建模考虑根号分治,钦定阈值 \(B\)

  • \(P_i\ge B\),则其能跳到的点不会超过 \(\frac{N}{B}\) 个,可以直接暴力枚举然后连向虚点。
  • \(P_i<B\),我不会,看来不能这样做了。

我无语了,状态数大法,第二种最多只有 \(N\sqrt{N}\) 中状态数。所以直接暴力 \(\text{01bfs}\) 是对的。

P3758/P5789

做一下矩阵的题目。

容易写出一个朴素的 dp。设 \(f_{u,i,0/1/2}\) 表示走到点 \(u\) 且为第 \(i\) 轮,且这一轮要进行停/走/爆炸的方案数。

转移平凡的:

\[f_{u,i,0/1/2}\leftarrow \sum_{v\in \text{from}_u} f_{v,i-1,1} \]

这样子的时间复杂度是 \(O((n+m)\times t)\) 的,显然需要优化。考虑建出邻接矩阵,然后进行矩阵加速。具体的,因为可以留在原地,这就相当于从 \(u\) 走到 \(u\),所以在邻接矩阵上给每一个点都连自环。

还是学习一下吧。邻接矩阵 \(A^k\) 表示图上任意两点 \(u\)\(v\) 经过 \(k\) 条边到达对方的方案数。现在只需要处理自爆这个东西就可以解决这道问题了。有办法了,可以建超级源点 \(0\),让每一个点都像 \(0\) 连一条单向边,这样便可以实现目的。哦,\(0\) 也要连自环,表示一直兜圈子。

时间复杂度:\(O(n^3\log k)\)

P8571

请开始你的挑战。

显然肯定是先离线,然后建 ACAM,然后不会了。

受到 CF587F 的启发,考虑根号分治一下。设 \(\sum|s_i|=m\),钦定阈值 \(B\),则:

  • \(|s_k|\ge B\),则将 \(s_k\) 的节点在 \(\text{fail}\) 树上标记为 \(1\),然后暴力枚举每一个 \(s_i\),查询其终止状态在 \(\text{fail}\) 树中子树的权值和。然后用线段树维护一下询问。则这部分的时间复杂度为:\(O(\frac{mn}{B}+q\log n)\)
  • \(|s_k|<B\),发现最终答案不会超过 \(B\) 且不同的答案不会超过 \(2B\) 种。所以考虑对于每一个 \(s_k\) 建立虚树,然后如果对于一个虚树上的点 \(u\),若存在 \(u\) 的一个祖先节点且该节点为询问 \(i\in [l, r]\) 区间中 \(s_i\) 的终止节点,则该次询问的答案至少为 \(sz_u\)。故考虑扫描线,把询问挂到 \(r\) 上去,每次枚举虚树中的点查答案就行了。判断是否存在 \(i\in [l, r]\) 只需要维护当前 \(\text{fail}\) 树中每一个节点对应的最大 \(i\)。所以可以用分块维护 \(\text{dfs}\) 序,然后在扫描线的时候将扫到的串串结束位置的子树取 \(\max\),每次询问单点查询。用 \(O(\sqrt{N})-O(1)\) 分块可以做到:\(O(m\log m+n\sqrt{m}+qB)\)

总时间复杂度为:\(O(\frac{mn}{B}+q\log n+m\log m+n\sqrt{m}+qB)\)。取 \(B=\sqrt{m}\),可以做到 \(O((n+q)\sqrt{m}+q\log n+m\log m)\)

posted @ 2026-03-02 13:09  Tomwsc  阅读(541)  评论(0)    收藏  举报