2024 syzx 冬季训练 5 - 数据结构

A

对于每种颜色分别做,\(x\)\(y\) 的贡献可以分别求和,排序即可。

B

二分答案,枚举最小值点,预处理出左右两边的最大贡献。

C

因为用到的操作只有求中位数,所以只用二分最终的答案,就可以把一开始大于等于 mid 的数视为 +1,小于 mid 的数视为 -1。再使用一些前缀和技巧模拟即可。

D

题意:定义 \(F(x)\) 为比 \(x\) 大的且二进制上 1 的个数小于等于 \(x\) 的最小的数。对于所有 \(F(x)\le n\),将 \(x\)\(F(x)\) 连边,得到一个森林。\(m\) 次操作,每次将一个点到所在树的根的路径上的点权加 \(v\),或者查询编号在 \(L\)\(R\) 之间的点的点权的和。

\(n\le 10^{18},m\le 10^5\)

发现 \(F(x)=x+lowbit(x)\),所以树高只有 log,先把所有单点修改都找出来,重新离线+离散化,再拿树状数组做一遍。

E

正解:

对于一个 \(d\),假设在 \([x, 3x]\) 内存在一盏灯满足条件,那么输出 \(1.5x\) 即可 保证结果正确。因此等价于找到最小的 \(k\) 满足答案位于 \([3k , 3 k+1)\),共 \(log_3 n\) 个区间。 对于一个区间 \([3k , 3 k+1)\),如何对于每个 \(d\) 判断是否存在一盏灯满足条件? 令 \(A_i\) 表示坐标为 \(i\) 且编号在 \([3k , 3 k+1)\) 中的灯的颜色,若不存在则为 0; 令 \(B_i\) 表示坐标为 \(i\) 的灯的颜色,若不存在则为 0。 则 \(d\) 有解当且仅当 \(\sum_i [A_i > 0][B_{i+d} > 0](A_i − B_{i+d}) ^2 > 0\)。反转 \(A\) 后拆掉平方为卷积的形式,FFT \(O(d \log d)\) 求解即可。 时间复杂度 \(O(d \log d \log n)\)

bitset 做法:

不需要使用模糊答案的性质。

枚举答案(从小到大枚举编号),维护当前已经出现的可行的距离 \(d\),使用除了当前颜色之外的颜色的 std::bitset 可以计算出新增答案的位置,只枚举这些新增的位置来更新答案即可。需要使用根号分治来优化空间。 时间复杂度 \(O ( n^2 /w )\)

F

题意:一棵树,每个点颜色 \(c_i\),你可以选择一条路径,把颜色排成一个序列,然后任取一个子序列,但是你需要保证这个子序列是回文的。求最终子序列的最大长度,\(n\le 200000\)

每种颜色出现次数不大于 2

正解:

设与点 \(u\) 的颜色相同的另一个点为 \(lnk_u\)。设 \(f_u\) 表示现在已经选了 \(u\)\(lnk_u\),最多选了多少。

使用刷表法转移 dp,\(f_u\) 可以转移到的 \((v,lnk_v)\) 在 dfs 序上是一个矩形。

线段树套线段树维护。

树剖做法:

选出的回文串其实有两个部分,第一个部分匹配的两个点是祖先关系,第二部分不是。

dp 的定义和正解一样,我们先对第一部分转移。我们对树进行 dfs,如果 \(lnk_u\)\(u\) 的祖先,则得到 \(f_u\) 之后把它插入到 \(dep_{lnk_u}\) 的位置,每次查询 \(dep_u\)\(dep_{lnk_u}\) 的最值。dfs 退出 \(u\) 的时候删除贡献。

第二部分类似,只不过查询时变成了路径查询,使用树剖。

(我怎么感觉这两个部分其实可以合并)

G

首先考虑如何计算固定的 \(k\) 的答案。将所有盘子按照 \(b\) 从小到大排序,枚举第 \(x (k ≤ x ≤ n)\) 个盘子作为选中的 \(b\) 最大的盘子,那么剩下的 \(k − 1\) 个盘子显然是贪心选择前 \(x − 1\) 个盘子 中 \(a\) 最小的 \(k − 1\) 个。给定 \(k\)\(x\),可以通过可持久线段树在 \(O(log n)\) 的时间内求出对应方案 的值 \(w(k, x)\)。 令 f(k) 表示使 \(k\) 取到最优解的 \(x\)。对于两个不同的决策 \(x, y (x < y)\),若 \(w(k, x) ≥ w(k, y)\), 那么增大 \(k\) 之后由于 \(y\) 的可选择范围严格包含了 \(x\) 的可选择范围,因此 \(y\) 新选的 \(a\) 值一定不 大于 \(x\) 所选的,即 \(w(k ′ , x) ≥ w(k ′ , y)\) 对于 \(k ≤ k ′ ≤ n\) 恒成立。由此可得 \(f(1) ≤ f(2) ≤ f(3) ≤ · · · ≤ f(n)\),最优决策具有单调性,可以分治求解,共需计算 \(O(n log n)\) 个$ w(k, x)$ 的值。 时间复杂度 \(O(n log^2 n)\)

H

先求出两个序列分别的异或和记为 \(A, B\),则修改位置 \(i\) 相当于让两者同时异或 ai ⊕ bi,则可以将所有 ai ⊕ bi 构造线性基。接下来从 A, B 的高位往低位考虑,对于一位:

  1. 如果都是 1,且线性基这一位有值,则同时异或线性基这一位,都变成 0 肯定更优。

  2. 如果都是 0,则不管。

  3. 如果一个 1 一个 0,后面肯定让这一位是 1 的尽可能小,0 的不用管,则用线性基贪心即可。如果 这一位线性基有值,那么需要枚举是否异或这个值,两种情况都往下贪一次即可。

时间复杂度为 O(n log w),其中 w 为值域。

I

注意到如果 \(query(a, b, c)\) 为真,那么 \(query(≥ a, ≥ b, c)\) 一定为真。 从小到大枚举询问中 a 的值,按横坐标从小到大依次加入每个点,维护 \(f_c\) 表示最小的 b 满 足 query(a, b, c) 为真。假设当前正在加入点 (x, y, w),有 \(f(c+w) mod n =\min(f(c+w) \mod n, \max(fc, y))\)。 观察状态转移方程可知,如果 \(y ≥ f(c+w) \mod n\),那么就没有更新的必要。令 \(m = max(f_0, f_1, . . . , f_{n−1)}\), 那么如果 y ≥ m,则这个点是完全无用的,可以直接跳过。 由于数据随机,可以近似地认为加入 k 个点后,所有 \(2^k\) 个子集和模 n 的结果在 [0, n) 等 概率均匀分布。可以看作 \(2^k\) 个小球随机放入 n 个洞之中,填满所有 n 个洞所需的期望球数 是 O(n log n),因此 k = O(log n) 时期望可以填满整个 f 数组。这说明,f 数组的最大值的 期望值等于所有已经加入的点的纵坐标的第 O(log n) 小值,即 O( n log n k )。 于是,加入的第 k 个点的纵坐标 y < m 的概率为 O( log n k ),期望只需要更新 \(O( ∑^n _{k=1} \frac{\log n}{k} ) = O(log^2 n)\) 遍 f 数组。由于这个值并不大,每次暴力 O(n) 更新整个数组即可。有了 f 数组就 可以很容易地求出最终的答案。 时间复杂度 O(n log^2 n)。

如果你没想到 \(f_c\) 表示最小值,你可以一边扫一边维护前 log 小的 yi(只算扫到的点的 y) 的背包,背包的值是 01,用 bitset 优化。时间 \(\mathcal{O}(n\log^3 n/\omega)\)

J

一个 \(m\times m\) 的网格,有一些矩形(端点都是整点),问拿走恰好两个矩形之后剩下矩形的交的面积的最小值。

统计每个格子被多少矩形覆盖。现在每个矩形内的 1 是拿走这个矩形一定可以带来的贡献。拿走两个矩形时,它们交集里面的 2 也会产生贡献。所以我们枚举 2 的格子,找到那两个矩形就能统计贡献。

问题是怎么找到那两个矩形?处理出每个格子被覆盖的矩形的编号和、编号平方和,就可以解方程解出那两个矩形的编号。

K

可以线段树维护哈希,开两棵树分别维护 \(A_i\) 正过来的哈希和 \(A_i\) 倒过来的哈希,每次线段树上二分就 好了。

由于值域比较大,可能需要双模/较大模数。

L

考虑枚举答案,再按在序列中的顺序枚举它的倍数。对于可能对答案有贡献的三元组 (i,j,k),一定满足 i与 j相邻,且 k是离 j最近的合法的标号。显然这样的三元组个数最多只有O(nd) 个。

接下来考虑怎么求每个三元组 (i,j,k)。一种写法是,因为对于一个枚举到的答案,随着 i的增加,k 是没有单调性的,所以想求出所有三元组只能二分答案。但是如果我们从右往左枚举 i,用双指针维护 k,虽然没有办法求出所有三元组,但对于每个错过的三元组 (i,j,k),一定存在一个三元组(i',j',k') 使得 i'<=i 且 k<=k'。所以我们错过的三元组一定不优。于是我们就可以在 O(nd) 的时间内求出所有合法三元组。

另一种常数更小的写法是:我们不直接枚举答案,而是从左往右扫,对每个数 ai 枚举它的因数 x。设上一 次出现 x的倍数的位置是 lst_x,这样所有在 2i-lst_x 后面的数 k都能组成 (lst_x,i,k) 且答案为 x 的 三元组。于是我们把 x挂在 2i-lst_x 上就可以方便地求出所有三元组 (i,j,k)。

接下来,我们离线询问,将三元组 (i,j,k)与对应的答案挂在 i或 k上,就只需要做一个二维数点。由于 \(\sqrt n\)与 d同阶,且要做 O(nd) 次修改和 O(q) 次查询,我们用 O(1) 修改 O(sqrt n) 查询的分块即可做到 \(\mathcal{O}(nd+n\sqrt n)\)的复杂度。

posted @ 2025-02-09 10:41  CHiSwsz  阅读(67)  评论(0)    收藏  举报