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

A

对于每种颜色分别做,xy 的贡献可以分别求和,排序即可。

B

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

C

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

D

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

n1018,m105

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

E

正解:

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

bitset 做法:

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

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

F

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

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

正解:

设与点 u 的颜色相同的另一个点为 lnku。设 fu 表示现在已经选了 ulnku,最多选了多少。

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

线段树套线段树维护。

树剖做法:

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

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

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

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

G

首先考虑如何计算固定的 k 的答案。将所有盘子按照 b 从小到大排序,枚举第 x(kxn) 个盘子作为选中的 b 最大的盘子,那么剩下的 k1 个盘子显然是贪心选择前 x1 个盘子 中 a 最小的 k1 个。给定 kx,可以通过可持久线段树在 O(logn) 的时间内求出对应方案 的值 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) 对于 kkn 恒成立。由此可得 f(1)f(2)f(3)···f(n),最优决策具有单调性,可以分治求解,共需计算 O(nlogn)w(k,x) 的值。 时间复杂度 O(nlog2n)

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 的值,按横坐标从小到大依次加入每个点,维护 fc 表示最小的 b 满 足 query(a, b, c) 为真。假设当前正在加入点 (x, y, w),有 f(c+w)modn=min(f(c+w)modn,max(fc,y))。 观察状态转移方程可知,如果 yf(c+w)modn,那么就没有更新的必要。令 m=max(f0,f1,...,fn1), 那么如果 y ≥ m,则这个点是完全无用的,可以直接跳过。 由于数据随机,可以近似地认为加入 k 个点后,所有 2k 个子集和模 n 的结果在 [0, n) 等 概率均匀分布。可以看作 2k 个小球随机放入 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(k=1nlognk)=O(log2n) 遍 f 数组。由于这个值并不大,每次暴力 O(n) 更新整个数组即可。有了 f 数组就 可以很容易地求出最终的答案。 时间复杂度 O(n log^2 n)。

如果你没想到 fc 表示最小值,你可以一边扫一边维护前 log 小的 yi(只算扫到的点的 y) 的背包,背包的值是 01,用 bitset 优化。时间 O(nlog3n/ω)

J

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

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

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

K

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

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

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上,就只需要做一个二维数点。由于 n与 d同阶,且要做 O(nd) 次修改和 O(q) 次查询,我们用 O(1) 修改 O(sqrt n) 查询的分块即可做到 O(nd+nn)的复杂度。

posted @   CHiSwsz  阅读(50)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 地球OL攻略 —— 某应届生求职总结
· 周边上新:园子的第一款马克杯温暖上架
· Open-Sora 2.0 重磅开源!
· 提示词工程——AI应用必不可少的技术
· .NET周刊【3月第1期 2025-03-02】
点击右上角即可分享
微信分享提示