杂题记录及简要题解(二)

以下是最近(2月15日之后)做的杂题总结,以省选题为主。部分省的部分题目是在之前完成的,所以这里没有列出。

[JSOI2018] 战争

凸包 (A) 在移动了向量 (vec{v}) 之后与凸包 (B) 有交,等价于存在两个点 (p_a, p_b),满足 (p_a in A, p_b in B),且 (p_a + vec{v} = p_b)。即 (vec{v} = p_b - p_a)。因此合法的向量 (vec{v}) 满足 (vec{v} in {p_b + (-p_a) | p_a in A, p_b in B})。对凸包 (A) 的所有点坐标取反后,求出凸包 (A) 与凸包 (B) 的闵可夫斯基和,这样,问题转化为判断一个点是否在一个凸包内,可以通过二分在 (O(log n)) 的时间内完成。

[JSOI2018] 防御网络

求期望可以转化为求方案数。我们将贡献分为两类:割边的贡献与环的贡献,然后分别讨论。

对于割边,记一条割边两边的结点数分别为 (s_1, s_2),显然只要两边各有至少一个结点被选择,当前这条割边就必然出现,因此该条割边出现的方案数为 ((2^{s_1} - 1)(2^{s_2} - 1))

对于每一个环,不好直接枚举计算任意一条环边必然出现的方案数。我们需要先求出去掉环边后以环上各个结点为根对应的子树大小,因为假设 (u) 为环上的结点,若以结点 (u) 为根的子树内的结点被选中,在该环上等价于结点 (u) 被选中。记环上的结点数为 (s),假设一种结点选择方案满足环上相邻两点的最大间距为 (k)(即两点之间的边数),那么我们只需要最少 (s - k) 条边就可以使得该环上所有已选择的点连通,因此对环上的结点重编号为 (1 sim s) 后,定义 (f_{l, r, x}) 表示当前选择的编号最小与最大的环上结点分别为 (l, r),只考虑编号在 ([l, r]) 内的结点,已经出现的最长间距为 (x) 的选点方案数。转移直接枚举在 ([l, r)) 内距 (r) 最近的点即可。当前环的最终贡献即为 (sum_limits{l = 1}^{s}sum_limits{r = l}^{s}sum_limits{x} f_{l, r, x} imes min{s - x, r - l})

[JSOI2016] 轻重路径

若一次修改的叶子结点为 (u),显然只有 (u) 到根的路径上的结点轻重儿子可能会发生变化,考虑暴力寻找这些结点并更新这些结点对答案的贡献。具体地,从根节点开始,设根节点为 (x),我们通过二分找到从 (u)(x) 的链上离 (x) 最近且满足 ({ m size}_v leq frac{1}{2}{ m size}_x) 的结点 (v)(其中 ({ m size}_x) 表示以结点 (x) 为根的子树大小),显然结点 (v) 的父亲是当前离 (x) 最近且轻重儿子可能会发生变化的结点,更新完其贡献后,将结点 (v) 设为 (x) 重复上述操作,即可找到所有可修改的点。由于每次找到的 (v) 较原来的 (x) 而言,( m size) 减少了至少一半,因此只会寻找最多 (log n) 次。

[HAOI2018] 字串覆盖

首先将串 (A)(B) 拼接后求出其后缀数组。然后进行数据分治,对于每次询问:

  • (K > sqrt n) 时,询问串在初始子串中的出现次数不会超过 (sqrt n) 次,每一次可以直接贪心地找可以匹配的最靠前的下标位置。求出询问串在后缀数组中对应的可匹配的的 ( m rank) 区间后,问题转化为在一段 ( m rank) 区间内查询一段下标区间中最小的下标。以后缀排名作为时间轴建主席树后可以在单次 (O(log n)) 的时间内完成查询。因此单次询问的时间复杂度为 (O(sqrt n log n))
  • (K leq sqrt n) 时,我们可以先预处理出这 (sqrt n) 种长度对应的状态。即预处理出在每一种长度下,每一个下标所对应的之后可匹配的最靠前的下标。显然这样的对应关系形成了一个树形结构(准确地说是森林结构),因此我们可以预处理出倍增数组。对于每次查询,直接从区间内最左边的合法下标开始在倍增数组上二分即可。对于单个长度而言,预处理的时间复杂度为 (O(n log n)),因此总预处理的时间复杂度为 (O(n sqrt n log n))

理论总时间复杂度为 (O((n + q) sqrt n log n))。不过由于数据的特殊性,数据分治的阈值最好设 (50) 左右而不是 (sqrt n)

[HAOI2018] 反色游戏

首先,每一个连通块内都包含偶数个黑点则必然有解(连通块均指极大连通块)。考虑单个连通块,假若其中存在偶数个黑点,那么我们可以将黑点两两配对,由于将配对的黑点间的路径上的所有边均进行取反操作后必然只会导致两个配对的黑点颜色改变,因此必然存在方案可以使得最终所有点变为白色。同时不难发现,若存在一个连通块内包含奇数个黑点则必然无解。

对于一个包含 (n) 个结点的连通块,将一条边看做一个长度为 (n) 的位向量,假设该条边连接结点 (u, v),那么位向量的第 (u) 位与第 (v)(1),其余位均为 (0)。由于根据上面的结论,一个初始局面中只要存在偶数个黑点(即偶数个 (1))必然有解,因此每一个有解的初始局面对应的向量必然可以通过选择一些边的向量异或得到。根据线性基的理论,选择边的集合得到每一个合法向量的方案数是相同的。换句话说,每一种有解的初始局面对应的选边方案数是相同的。由于有解的初始局面数量为 (2^{n - 1}),选择边集的总方案数为 (2^m),因此每一种有解的初始局面对应的方案数都为 (2^{m - n + 1})。那么对于多个连通块而言,每种有解的初始局面对应的方案数即为 (2^{m - n + p}),其中 (p) 为连通块的数量。

对于删掉每一个点的情况,通过求割点判断一下连通块的增加数量以及每个连通块是否合法即可算出删掉该点后的答案。

[HAOI2017] 新型城市化

对原图的边集取补集后,问题转化为求删掉哪些边后,原图点集的最大独立集会增大。根据二分图最大点独立集的求法,原题等价于求哪些边必然在最大匹配中,建出网络后,也即求哪些边删掉后,最小割会变小。其方法可参考 [AHOI2009]最小割,这里不再赘述。

[HAOI2017] 方案数

在忽略禁止点的情况下,不难发现转移到一个点的方案数只与这个点的坐标中各个数字的二进制中 (1) 的数量有关。因此可以先定义 (f_{i, j, k}) 表示走到一个点 ((x, y, z)) 满足 (x) 的二进制中包含 (i)(1)(y) 的二进制中包含 (j)(1)(z) 的二进制中包含 (k)(1) 的方案数。使用组合数转移即可。

现在考虑禁止点。由于禁止点数 (o leq 10^4),支持 (O(o^2)) 的算法,因此对于每一个禁止点,可以直接暴力枚举可能与之冲突的禁止点,做容斥减掉对应方案即可。

[HAOI2017] 供给侧改革

随机串满足串的两个起始位置不同的后缀的 lcp 不会太长。记长度阈值为 (L)(L)(40) 左右),那么我们可以将询问离线,按右端点排序后,将每一个位置开始的长度为 (L) 的子串插入到一棵 trie 中,并在过程中维护每一个长度的 lcp 对应的两个串的最晚出现位置。对于以当前位置为右端点的询问,根据维护的最晚位置在 (O(L)) 的时间内统计答案即可。总时间复杂度为 (O((n + Q)L))

[HAOI2016] 地图

前面的点双部分是硬套的,可以建圆方树求 dfs 序后,将问题转化为多次询问求给定区间内值域在 ([1, y]) 且出现次数为奇/偶的数值共有多少种。

对于常规的莫队算法,移动端点的总时间复杂度为 (O((n + m) sqrt n)),而单次查询的时间复杂度往往是 (O(1)) 的,即时间复杂度的瓶颈往往不在查询上。在本题中,我们就可以考虑使用时间复杂度略高的查询方法。具体地,我们可以再对值域分块,在移动端点时 (O(1)) 地更新块内信息,在查询时 (O(sqrt n)) 地查询所有值域块,这样即可使用莫队在时间复杂度不变的情况下实现题目所述的查询。

[HAOI2016] 字符合并

直观的想法是定义 (f_{l, r, s}) 表示原串的区间 ([l, r]) 对应的子串最后合并为 (s) 的最优分数。转移时枚举 (x),表明 (s) 的最后一位由区间 ([x, r]) 合并得到。时间复杂度为 (O(n^32^k))

注意到对于区间 ([l, r]),在经过若干次合并后最终得到的串长一定为 ((r - l) { m mod} (k - 1) + 1)。换句话说,区间 ([x, r]) 能合并成一个字符当且仅当 ((r - x) equiv 1 ({ m mod} (k - 1))),因此枚举 (x) 时每次可以跳 (k - 1)。最终时间复杂度为 (O(frac{n^32^k}{k}))。由于许多状态不会出现在 dp 转移中,因此可过。

[HAOI2015] 数字串拆分

由于 (f(x) = sum_limits{i = 1}^m f(x - i)),显然可以构造一个 (m imes m) 的转移矩阵后,使用矩阵快速幂来求 (f(x))

定义 (h(x)) 表示 (g(S_{1 sim x})),那么答案即为 (h(n)),注意 (h(x)) 是以矩阵的形式存储的。不难得到转移:(h(x) = sum_limits{y = 1}^{x} h(y - 1) imes { m tran}_{y sim x})。其中 ({ m tran}_{l sim r}) 表示 (S_{l sim r}) 对应的 (f) 的转移矩阵。我们可以先预处理出所有 (S_{l sim r}(1 leq l leq r leq n)) 对应的 (f) 的转移矩阵,具体地,类似于倍增,我们可以预处理出所有满足 (x = a imes 10^b)(f(x)) 的转移矩阵,这样,({ m tran}_{l + 1 sim r}) 只需乘以 (a = S_{l sim l}, b = r - l) 对应的转移矩阵即可得到 ({ m tran}_{l sim r})

[JOISC2016] 俄罗斯套娃

先不考虑题目所给的询问限制,只考虑如何在给定所有套娃的情况下,求经过若干次嵌套后,没有被套的套娃的最小数量。根据 Dilworth 定理:偏序集最小链覆盖等于最长反链,问题转化为求最多可以找出多少个套娃满足:根据题目所给的嵌套关系,这些套娃可以依次嵌套。将所有套娃按直径从大到小排序,高度从小到大排序后,依次扫描,用树状数组维护前缀最大值来计算以每个点作为反链起点的答案即可。

加入询问后,将询问和所有套娃一起离线即可。

[HNOI2018] 毒瘤

由于 (m - n) 较小,因此可以先选 (n - 1) 条边构成一棵树。这之后,朴素的想法是再枚举所有非树边的状态,然后暴力做一次树形 dp 统计答案,时间复杂度为 (O(n2^{m - n}))(注意一条边 ((u, v)) 应只考虑对应两种状态,即强制 (u) 点选与 (u) 点不选,而不是三种状态,否则时间复杂度会升高为 (O(n3^{m - n})))。

注意到上述做法重复计算了许多部分的 dp 值。具体地,我们考虑对与这 (m - n + 1) 条非树边有关的点建虚树,那么除开虚树上的结点后,剩下的原树上的连通块的 dp 值在枚举每一次非树边状态时都进行了一次计算。显然这些连通块的 dp 值我们可以先预求得到,之后直接枚举非树边状态后再做一次虚树 dp 即可。时间复杂度为 (O(n + (n - m)2^{n - m}))

[HNOI2018] 寻宝游戏

不难发现,当 (x) 为任何数((0 / 1))时,均有:

  • 对于或运算:(x | 1 = 1, x | 0 = x)
  • 对于与运算:(x & 0 = 0, x & 1 = x)

只考虑第 (i) 位数。若第 (i) 位最终为 (1),那么必然满足:最后一个“(|1)”操作的位置必然在最后一个“(&0)”操作的后面。否则最后一位即为 (0)。我们将运算也视为二进制数,具体地,将或运算视为 (0),与运算视为 (1)。为了方便,不妨将提取出 (a_1, a_2, cdots, a_n) 的第 (i) 位得到的数字串称为串 (x_i),将运算数字串称为串 (y)。那么第 (i) 位最终为 (1) 必然满足:串 (x_i) 与串 (y) 的最后一个不相同的位 (j) 满足 ((x_i)_j = 1, y_j = 0)。如果我们定义串的最后一位为二进制数的最高位,那么上述描述等价于:当串 (x_i) (>)(y) 时,第 (i) 位最终为 (1)。对应地,当串 (x_i) (leq)(y) 时,第 (i) 位最终为 (0)

这样,假设对于一次询问串,需满足串 (x_i) (>)(y)(即询问串的第 (i) 位为 (1))的最小的串 (x_i) 为串 (x_min), 需满足串 (x_i) (leq)(y)(即询问串的第 (i) 位为 (0))的最大的串 (x_i) 为串 (x_max),那么 (x_min - x_max) 即为答案。注意特判边界及无解的情况。

[HNOI2017] 大佬

不难发现回复自信与打击大佬两类操作是完全独立的。因此可以先通过简单的 dp 求出最多能有多少天来打击大佬(不妨假设为 (T) 天)。这里定义打击大佬的操作包括:还嘴、增加等级、讽刺能力乘以等级、怼大佬。

由于可能出现的讽刺能力的数量是很少的。因此我们可以先 bfs 出所有 (T) 天内可能出现的讽刺能力。假设可能出现讽刺能力 (x),且得到该讽刺能力的最小天数为 (t(x)),那么我们的目的是判断是否存在两个讽刺能力 (a, b),满足 (a + b leq C),且 (a + b + T - t(a) - t(b) geq C)(即对大佬直接进行两次讽刺能力分别为 (a, b) 的攻击,剩余的部分用还嘴操作来解决)。假设不同的讽刺能力的总数量为 (S),那么判断是否满足上述条件的 (a, b) 可以通过对所有二元组 ((x, t(x)))(x) 从大到小排序后使用双指针法在 (O(S)) 的时间内解决。当然,只使用一次怼大佬甚至是不使用的情况也是有可能出现的,特判该类情况即可。

[HNOI2017] 单旋

本题的一个重要特点就是旋转操作只针对最值。不妨记 splay 根结点的深度为 (0)。分析 splay 的操作,不难发现如下性质:假若将当前 splay 的最小值结点 (u_{min}) 旋转到根,那么 (u_{min}) 的深度将变为 (0)(u_{min}) 的右子树(如果存在)内的所有结点相对位置不变且深度不变,其余结点的相对位置不变且深度均 (+1);假若将当前 splay 的最大值结点 (u_{max}) 旋转到根,那么 (u_{max}) 的深度将变为 (0)(u_{max}) 的左子树(如果存在)内的所有结点相对位置不变且深度不变,其余结点的相对位置不变且深度均 (+1)。考虑用线段树维护每个结点的深度,这样一次单旋操作只需对应地在线段树上进行一次单点修改与区间增加操作即可。

接下来考虑插入操作。记当前插入的数为 (x),已经存在的数中,小于 (x) 且最大的数为 ({ m pre}_x),大于 (x) 且最小的数为 ({ m suf}_x)。显然在插入 (x) 后,在 splay 上 (x) 要么是 ({ m pre}_x) 的右儿子,要么是 ({ m suf}_x) 的左儿子,且若 ({ m pre}_x) 的深度更大,那么 (x)({ m pre}_x) 的右儿子,反之即为 ({ m suf}_x) 的左儿子。因此,我们只需用一个 set 来便于查询 ({ m pre}_x)({ m suf}_x),再结合旋转操作维护的线段树,即可知道插入 (x) 后结点 (x) 的位置。

然而,只用一棵线段树并不能完全解决此题。由于我们在旋转时需要确定 (u_{min})(u_{max}) 的左/右儿子以及父结点的值,才能在线段树上做对应的区间修改。因此我们还需要维护出这棵 splay 的具体形态。不过由于插入操作与旋转操作都不会对 splay 的结构造成太多的影响,因此我们只需要做对应的模拟即可。换句话说,我们不必完整地实现 splay 的各个函数。

[HNOI2016] 大数

(f_{x}) 表示子串 (S_{x sim N}) 对应的数字。那么 (S) 的子串 (S_{l sim r}) 对应的数字为 (p) 的倍数等同于 (frac{f_l - f_{r + 1}}{10^{N - r}})(p) 的倍数。

  • (p eq 2)(p eq 5) 时:由于 (f_l - f_{r + 1}) 在乘以了 (frac{1}{10^{N - r}}) 后不会影响除了 (2, 5) 的质数在 (f_l - f_{r + 1}) 中的出现与否。因此,此时 (frac{f_l - f_{r + 1}}{10^{N - r}} { m mod} p = 0 Leftrightarrow (f_l - f_{r + 1}) { m mod} p = 0)。这样,单次询问转化为求 ( m [fr, to + 1]) 中共有多少对 (i, j) 满足 (f_{i} equiv f_{j} ({ m mod} p)) (({ m fr} leq i < j leq { m to} + 1))。使用莫队算法即可。
  • (p = 2) 时,显然一个子串是 (p) 的倍数当且仅当子串以 (0, 2, 4, 6, 8) 结尾。用线段树统计贡献即可。
  • (p = 5) 时,显然一个子串是 (p) 的倍数当且仅当子串以 (0, 5) 结尾。同上用线段树统计贡献即可。

[HNOI2016] 最小公倍数

问题等价于对于每个询问,求在加入满足所有 (a_i leq a) 以及 (b_i leq b) 的边 (i) 后,结点 (u)(v) 是否连通,且是否满足连通块内的 (max{a_i} = a, max{b_i} = b)

考虑分块。将所有边及询问放到一起后按照 (a) 为第一关键字,(b) 为第二关键字从小到大排序后,按每 (x) 项分为一块,并依次处理每一块。在处理第 (k) 个块时,将块内的所有询问按 (b) 从小到大排序,同时将前 (k - 1) 块的所有边按 (b) 从小到大排序。对于每个询问,我们需要找出所有合法的边。在前 (k - 1) 块中,由于所有边的 (a) 一定合法(即不会超过当前询问的 (a)),且所有边已按 (b) 从小到大排序,因此只需使用一个指针来维护对于当前询问,(b) 也合法的边的位置;在当前块中,我们可以直接暴力枚举所有边,找出合法边即可。判断是否连通以及记录连通块内的最值信息可以用并查集实现,不过由于块内的边在处理每一次询问时需要重新枚举,因此需要使用可撤销并查集。

考虑这样实现的时间复杂度。记 (m = n + q),由于单个块的大小为 (x),因此块的数量为 (frac{m}{x})。忽略并查集的复杂度,总时间复杂度为 (O(frac{m}{x} imes m log m) + O(frac{m}{x} imes (x^2 + m)) = O(frac{m^2 log m}{x} + mx))。根据均值不等式,(frac{m^2 log m}{x} + mx) 取得最小值满足:

[frac{m^2 log m}{x} = mx Leftrightarrow x = sqrt{m log m} ]

此时时间复杂度为 (O(msqrt {m log m}))

[THUWC2017] 随机二分图

首先考虑只有 0 类型的边的情况。

我们可以定义状态 (f_{S_1, S_2}) 表示左右两个点集已经匹配的结点集合分别为 (S_1)(S_2) 时构成完美匹配的方案数。记 (S_1) 中编号最小的结点为 (u),转移时直接枚举与结点 (u) 有关的连边即可。这样的状态数量似乎为 (sum_limits{i = 0}^{n} inom{n}{i}^2),但由于转移时强制选择与 (S_1) 中编号最小的点有关的连边,第一维的状态会因此受到诸多的限制,因此总状态数变得可接受。

接下来考虑存在 1 类型与 2 类型的边的情况。

  • 对于 1 类型的边,假设我们仍将其当成两条零类边处理。如果这两条边可以同时存在(即 (a_1 eq a_2)(b_1 eq b_2)),那么它们同时出现的概率就是 (frac{1}{4})。然而,我们需要的概率为 (frac{1}{2}),因此,我们再强制加一条同时包含这两条边的特殊的“边”,其出现概率为 (frac{1}{4})。这样,同时包含这两条边的完美匹配会被计算两次,每次这两条边贡献的概率均为 (frac{1}{4}),因此等价于其有 (frac{1}{2}) 的概率同时出现。显然,这样的做法不会影响完美匹配中只出现这两条边中的一条的情况,因为基于 0 类型边的做法,其对答案的贡献仍为 (frac{1}{2})
  • 对于 2 类型的边,假设我们也将其当成两条零类边处理。如果这两条边可以同时存在,那么它们就会有 (frac{1}{4}) 的同时出现的概率。然而,同时出现的情况不应该出现,因此,我们再强制加一条同时包含这两条边的特殊的“边”,其出现概率为 (-frac{1}{4})。这样,同时包含这两条边的完美匹配会被计算两次,且这两条边贡献的概率分别为 (frac{1}{4})(-frac{1}{4}),因此等价于其同时出现的概率为 (0)。其余内容同上。

[THUSC2017] 巧克力

显然的结论是,最优解必恰好包含 (5) 种不同的颜色。如果所有巧克力的图案种数在可状压的范围内,那么直接做斯坦纳树即可。

我们可以对每种图案随机一个 (1 sim 5) 的编号来降低状态种数,从而达到可状压的目的。假设最优解所对应的 (5) 种图案分别为 (a_1 sim a_5),那么当 (a_1 sim a_5) 分别得到了不同的编号时,我们必然能求出最优解(因为在其他情况下,我们不可能求出优于最优解的答案)。单次随机使得 (a_1 sim a_5) 得到不同编号的概率是 (frac{5!}{5^5} approx 0.0384)。当随机次数达到 (100) 次时,正确率可以达到 (1 - (1 - 0.0384)^{100} approx 98 \%)

[ZJOI2017] 仙人掌

存在解的前提条件是原图为仙人掌。由于新添加的边应满足不能跨越任何一个环,因此加边只会发生在去掉所有环后各个连通块(即各棵树)内部。我们考虑去掉环后,对每一棵树做树形 dp。注意到如果我们在添加一条连接结点 (u) 与结点 (v) 的边后,将结点 (u) 到结点 (v) 在原树上唯一简单路径上的所有边划分为一个集合,那么问题等价于求将整棵树的所有边划分为若干集合,使得每条边属于且仅属于一个集合,且每个集合的所有边能构成一条简单路径的方案数。

(f_u) 表示以结点 (u) 为根的子树内的合法划分方案数。令 ({ m son}(u)) 表示结点 (u) 的子结点集合,不难推出转移:

[f_u = sum_limits{i = 0}^{leftlfloorfrac{|{ m son}(u)|}{2} ight floor} inom{|{ m son}(u)|}{2i}g_{2i}(|{ m son}(u)| - 2i + 1)prod_limits{v in {{ m son}(u)}}f_v ]

其主要思路是先确定 (u) 的所有子结点集合的合并配对关系,再考虑 (u)(u) 的父结点的这条边是划分入 (u) 的子结点中剩下未合并的集合之一,还是单独划分一个集合。

其中的 (g_x) 表示 (x)(x) 为偶数)个不同的元素两两配对,使得每个元素均恰好属于一个匹配的方案数。通过考虑新增的两个元素是单独配对还是与之前的 (x - 2) 个元素配对,不难得到 (g_x(x geq 4)) 的递推式为:

[g_x = g_{x - 2} + (x - 2)(x - 3)g_{x - 4} ]

数组 (g) 可以提前预处理得到。最终答案即为各棵树的 dp 值的乘积。

[ZJOI2016] 小星星

朴素的想法为定义 (f_{i, j, S}) 表示结点 (i) 选择了编号 (j),且结点 (i) 的子树内的所有结点选择的编号集合为 (S) 时的方案数。这样强制通过记录子树已选的编号集合来限制当前结点的编号选择,往往免不了子集枚举,因此复杂度会带有 (3^n) 这一项。

注意到在忽略点集 (S),每个点在保证连边合法的情况下,可任意选择编号时,做一次 dp 的复杂度为 (O(n^3))。单次 dp 的时间复杂度不高,因此考虑使用容斥原理来降掉子集枚举的复杂度。具体地,令 (h_{S}) 表示所有结点选择的编号在集合 (S) 以内时合法的方案数,那么答案为 (sum_limits{|S| = n} h_{S} - sum_limits{|S| = n - 1} h_{S} + sum_limits{|S| = n - 2} h_{S} - cdots)。也即我们需要做 (2^n) 次 dp,因此总时间复杂度为 (O(2^nn^3))

[ZJOI2016] 旅行者

将所有询问离线后对整个矩形和所有询问分治。

具体而言,对于当前矩形,若其行编号范围为 ([l_x, r_x]),列编号范围为 ([l_y, r_y]),且有 (r_x - l_x < r_y - l_y)(否则交换行列即可),那么取出所有坐标为 ((x, frac{l_y + r_y}{2})) 的点作为中转点,并依次以每个中转点为源点跑单源最短路,然后更新当前矩形内所有询问的答案。这之后,我们可以沿着所有中转点所在的直线将当前矩形分成行编号范围为 ([l_x, r_x]),列编号范围分别为 ([l_y, frac{l_y + r_y}{2} - 1])([frac{l_y + r_y}{2} + 1, r_y]) 的两个矩形,将询问分组后分治处理这两个矩形即可。

这样做的正确性不难验证,考虑其时间复杂度。

对于询问的处理,由于一个询问只会被最多 (log (nm)) 个矩形包含,因此复杂度是 (O(q log(nm))) 的。接下来考虑跑最短路的总时间复杂度。

对于一个 (n)(m) 列的矩形,设 (nm = S),不难发现,其中转点的数量为 (min{n, m}),当出现最坏情况 (n = m) 时,转点数量为 (sqrt S)。若使用 Dijkstra 算法跑最短路,那么对于当前矩形,复杂度为 (O(Ssqrt S log S))。若所有情况均达到复杂度上界,那么有 (T(S) = 2T(frac{S}{2}) + S sqrt S log S)。拆开递归部分,可以得到:

[egin{aligned} T(S) &= S sqrt S log S + S sqrtfrac{S}{2} (log S - 1) + S sqrt frac{S}{4}(log S - 2) + cdots\ &<Ssqrt S log S + S sqrtfrac{S}{2} log S + S sqrt frac{S}{4}log S + cdots approx S(sqrt S + frac{sqrt S}{sqrt 2} + frac{sqrt S}{sqrt 4} + cdots) log S= O(S sqrt S log S) end{aligned} ]

由于 (S leq 2 imes 10^4),因此复杂度是可接受的。

[SCOI2015] 小凸想跑步

记凸包的第 (i) 个点为 (P_i)

注意到对于任意的 (i > 0),使得 (S_{Delta P_0P_1p} = S_{Delta P_iP_{i + 1}p}) 成立的所有点 (p) 一定构成一条直线,也即使得 (S_{Delta P_0P_1p} < S_{Delta P_iP_{i + 1}p}) 成立的所有点 (p) 一定构成一个半平面。我们可以直接计算或者二分求出这条直线,之后将求出的所有 (n - 1) 条直线与原凸包做半平面交即可求出合法点 (p) 所在的凸包。将求得的合法凸包面积与原凸包面积相除即为合法概率。

[SCOI2015] 小凸解密码

将环上问题放在倍长序列上处理。对于每次询问,二分答案后,问题转化为判断一段区间内是否有独立的一段 (0) 区间。可以用线段树维护区间内 (0) 区间的数量,再判断一下边界情况即可。对于修改操作,由于修改位置很少,因此可以直接线段树上暴力单点修改。时间复杂度为 (O(n + m log^2 n))

[BJOI2018] 链上二次求和

记结点 (k) 的权值为 ({ m value}_k)(S_k = sum_limits{i = 1}^{k} { m value}_i)(S'_k = sum_limits{i = 1}^k S_i)

对于一次询问,将答案式子暴力拆开:

[egin{aligned}& sum_limits{i = l}^r sum_limits{j = i}^{n} (S_j - S_{j - i}) \ =& sum_limits{i = l}^r sum_{j = i}^n S_j - sum_limits{i = l}^r sum_{j = 0}^{n - i} S_j \ =& sum_{i = l}^r (S'_n - S'_{i - 1}) - sum_{i = l}^r S'_{n - i} \ =& (r - l + 1)S'_n - sum_{i = l- 1}^{r - 1} S'_i - sum_{i = n - r}^{n - l}S'_i end{aligned} ]

由于 (S') 即为 ( m value) 的二维前缀和,因此需要解决的根本问题即为实现一个序列的区间加操作与查询该序列的二维前缀和的区间和。

假设一次区间加操作的操作区间为 ([l, r]),通过推导可以发现,该次操作对区间 ([l, r]) 内二维前缀和的影响是一个以下标 (i) 作为自变量的二次函数,对区间 ([r + 1, n]) 内二维前缀和的影响是一个以下标 (i) 作为自变量的一次函数。因此,用线段树维护区间各次项系数和以及函数值总和即可。

[BJOI2018] 二进制

不难推出如下结论:一个子串经过重新排列后能成为 (3) 的倍数,必然满足如下条件之一:

  • 区间内包含偶数个 (1)
  • 区间内包含奇数个 (1),且 (1) 的数量至少为 (3)(0) 的数量至少为 (2)

可以直接用线段树维护区间信息。具体地,可以维护区间内包含奇数/偶数个 (1) 的合法子串数量,以及以区间左端点/右端点作为子串端点,出现了奇数/偶数个 (1) 且满足某些限制条件(例如:(1) 的数量为 (0)(1)(2)(geq 3))的子串数量。合并区间时将信息逐条合并,并重新计算新增加的合法子串数量即可。

[SNOI2017] 一个简单的询问

给出的答案式子不好直接用莫队做。考虑将答案式子拆开:

[egin{aligned} &sum_{x = 0}^{infty}{ m get}(l_1, r_1, x) imes { m get}(l_2, r_2, x) \ = & sum_{x = 0}^{infty} ({ m get}(1, r_1, x) - { m get}(1, l_1 - 1, x)) imes({ m get}(1, r_2, x) - { m get}(1, l_2 - 1, x)) \ = & sum_{x= 0}^{infty} ({ m get}(1, r_1, x) imes { m get}(1, r_2, x) - { m get}(1, r_1, x) imes { m get}(1, l_2 - 1, x) - { m get}(1, l_1 - 1, x) imes { m get}(1, r_2, x) + { m get}(1, l_1 - 1, x) imes { m get}(1, l_2 - 1, x))end{aligned} ]

这样,就将一次询问的式子拆成了四个形如 (sum_limits{x = 0}^infty{ m get}(1, a, x) imes { m get}(1, b, x)) 的式子。而求 (sum_limits{x = 0}^infty{ m get}(1, a, x) imes { m get}(1, b, x)) 可以使用莫队算法直接完成,因此整个问题得以解决。

[SNOI2017] 遗失的答案

首先显然应满足 (G | L)。假设对 (G, L) 做唯一分解得到:

[G = p_1^{alpha_1}p_2^{alpha_2} cdots p_m^{alpha_m} \ L = p_1^{eta_1}p_2^{eta_2} cdots p_m^{eta_m} ]

对于一个包含 (n) 个数 (a_1, a_2, cdots , a_n) 的集合 (S),若 (S) 内所有数的最大公约数为 (G),同时最小公倍数为 (L),当且仅当满足如下所有条件:

  • (G | a_i, a_i | L(1 leq i leq n))
  • 记所有 (a_i(1 leq i leq n)) 的唯一分解中,(p_k) 的最小指数为 (gamma_k(1 leq k leq m)),则 (min{gamma_k} = alpha_k, max{gamma_k} = eta_k)

我们可以先搜索出所有满足上述条件的数,设满足上述条件的数的数量为 (s)。当 (L leq 10^8) 时,(s) 不会超过 (768),且在 (L) 中出现的不同的质因子的数量不会超过 (8)。因此我们定义 (f_{i, S_1, S_2}) 表示从前往后考虑到第 (i) 个数时,指数 (gamma_k) 已满足 (min{gamma_k} = alpha_k) 限制的质因子集合为 (S_1),已满足 (max{gamma_k} = eta_k) 限制的质因子集合为 (S_2) 时合法的选数方案数;(g_{i, S_1, S_2}) 表示从后往前考虑到第 (i) 个数时,对应的方案数。考虑如何计算必然包含某一个数的合法选数方案数,使用补集转化,必然包含某一个数的合法方案数即为总合法方案数减去不包含该数的合法方案数。记该数在所有合法的 (s) 个数中的下标为 (i),那么总合法方案数即为 (f_{s, 2^m - 1, 2^m - 1})(或 (g_{1, 2^m - 1, 2^m - 1})),不包含该数的合法方案数即为 (sum_limits{(s_1 |s_3) = (s_2 |s_4) = 2^{m} - 1} f_{i - 1, s_1, s_2} imes g_{i + 1, s_3, s_4}),显然这是一个集合并卷积的形式,因此,使用 FMT 即可在 (O(m4^{m})) 的时间内求出必然包含单个数的合法选数方案数。

理论上,总时间复杂度为 (O(sm4^{m})),但由于 (s = 768)(m = 8) 是两种不同的上界,不会同时取到,因此实际复杂度会更低。

[SDOI2017] 相关分析

对于一次询问,将答案式子暴力拆开:

[egin{aligned}& frac{sum_limits{i = l}^{r}(x_i - ar{x})(y_i - ar{y})}{sum_limits{i = l}^{r}(x_i - ar{x})^2} \ =&frac{sum_limits{i = l}^r x_iy_i - frac{1}{r - l + 1}sum_limits{i = l}^r sum_limits{j = l}^r x_iy_j}{sum_limits{i = l}^r x_i^2 - frac{1}{r - l + 1}sum_limits{i = l}^r sum_limits{j = l}^r x_i x_j}end{aligned} ]

那么我们需要维护 (sum x_i, sum y_i, sum x_iy_i, sum x_i^2) 四种值。区间加操作很好处理,注意一下四种值的维护顺序即可。区间赋值操作略显棘手,注意到我们可以将一次区间赋值操作拆成两个操作:先执行区间赋值操作 (x_i = i, y_i = i),再执行区间加操作 (x_i = x_i + S, y_i = y_i + T)。对于前者,由于每一个线段树区间在经过区间赋值操作 (x_i = i, y_i = i) 后各项的值都是固定的,可以 (O(1)) 计算得到,因此再额外记录一个区间覆盖标记即可。

[SDOI2016] 储能表

考虑数位 dp。

定义状态 (f_{p, 0/1, 0/1, 0/1}) 表示从高到低考虑到了第 (p) 个二进制位,且 (i) 的第 (p) 位至最高位构成的数已经/没有达到 (n) 的上界、(j) 的第 (p) 位至最高位构成的数已经/没有达到 (m) 的上界、(i, j) 的异或值已经/没有达到 (k) 的下界的情况下所有可能的 (i, j) 的异或值的总和,(g_{p, 0/1, 0/1, 0/1}) 表示同样条件下所有可能的 (i, j) 的方案数的总和。转移直接枚举当前位 (i, j) 的值即可。由于在保证了下界的情况下所有得到的异或值都不会小于 (k),因此答案即为所有合法情况的异或值总和减去合法方案数( imes k)

[SDOI2016] 游戏

显然每次在一条链上插入的是一个以 ( m dis) 为自变量的一次函数,可以树剖后用李超树维护。由于询问是区间询问,因此还需要维护区间函数最小值。一个区间的函数最小值要么来自当前区间的左右子区间的函数最小值,要么来自当前区间维护的直线的左右端点处的函数值。在插入直线时顺便维护即可。

[CF932F] Escape Through Leaf

(f_u) 表示结点 (u) 的答案,那么有 (f_u = min_limits{v in { m subtree}(u), v eq u}{a_ub_v + f_v}),注意到该转移式比较特殊,求 (f_u) 可以转化为求若干条形如 (y = b_vx + f_v) 的直线在 (x = a_u)(y) 的最小值,用李超树维护即可。由于是树上问题,因此需要使用线段树合并来合并子树信息。

[CF1097F] Alex and a TV Show

思路十分巧妙的转化。

(f(x)) 表示因子包含 (x) 的数的出现次数,(g(x)) 表示 (x) 的出现次数,那么有:

[f(x) = sum_limits{x |d}g(d) Rightarrow g(x) = sum_limits{x | d} mu(frac{d}{x}) f(d) ]

题目中的操作 4 即为求 (g(v))。考虑对于每一个 (v),都维护一个 (mu) 数组,如果我们知道了集合对应的 (f) 数组,那么只需将 (f)(v) 对应的 (mu) 做狄利克雷卷积即可。因此当前的问题是如何快速维护集合对应的 (f)

首先注意到由于只需要求答案的奇偶性,一切数组的维护都可以用 bitset 实现。接下来,分别考虑每一个操作:

  • 对于操作 1:直接将所有满足 (v | d)(f(d)) 赋为 (1),其余的 (f(d)) 赋为 (0) 即可。
  • 对于操作 2:只需将集合 (y)(z) 对应的 (f) 简单相加即可得到集合 (x) 对应的 (f)。在模 (2) 意义下,加法等同于异或运算。
  • 对于操作 3:考虑若在集合 (A) 中存在 (a)(v) 的倍数,在集合 (B) 中存在 (b)(v) 的倍数,由于若 (v | c, v |d),必有 (v | { m gcd}(c, d)),因此在两个集合相乘后,共会有 (ab)(v) 的倍数。因此只需将集合 (y)(z) 对应的 (f) 的各项简单相乘即可得到集合 (x) 对应的 (f)。在模 (2) 意义下,乘法等同于与运算。
  • 对于操作 4:直接将集合 (x) 对应的 (f)(v) 对应的 (mu) 数组做狄利克雷卷积即可。注意到我们可以通过交换 (v) 对应的 (mu) 数组中下标为 (frac{d}{v}) 的值与下标为 (d) 的值,使得我们所需的狄利克雷卷积式子成为 (sum_limits{v | d}mu(d)f(d)),这样,又转化为了将两个数组各项简单相乘,同操作 3,直接对两个 bitset 做与运算即可。

[CF1110H] Modest Substrings

朴素的做法是找出所有合法串然后在 AC 自动机上做简单 dp。然而由于合法串可能很多,因此我们并不能够将所有合法串都插入 trie 树内。

注意到合法的数字串满足其对应的数字位于一段区间内。考虑在平常做数位 dp 时,我们经常考虑上下边界问题。当从最高位开始已确定的数字满足既没有抵达上边界,又没有抵达下边界时,剩下的所有位的数字就可以任意填了。藉由该思路,我们考虑只搜出一些“确定串”:假设从最高位开始,已经确定的数字构成了一个“确定串”,那么剩下的数字可以任意填,同时,任意一个合法的数字串的开头(即从最高位开始)包含且仅包含唯一的“确定串”。

显然,“确定串”的数量只有 (O({ m len}(l) + { m len}(r))) 个,其中 ({ m len}(S)) 表示数字串 (S) 的长度。这样,我们可以只将所有“确定串”以及其对应的贡献放到 trie 树上。建出 AC 自动机后做 dp 即可。不过注意到一个“确定串”能否产生贡献还与数字串剩下未确定的位数有关,因此在记录“确定串”贡献时还应添加长度这一维,并计算前缀和,使用前缀和进行转移。

原文地址:https://www.cnblogs.com/ImagineC/p/10437722.html