跳至主要內容

Codeforces 3400 题目乱刷

Wallbreaker5th大约 9 分钟OI×ICPCOI×ICPCOI×ICPC - 题解

注意

题解写的可能非常抽象。

「如果一个题解你看不懂,那是题解垃圾而不是你垃圾。」

CF1010F Tree

2024-04-21

题意

给定一棵 nn 个点的有根树,保证每个节点有不超过两个儿子。你要首先选出一个包含根的连通块,然后给每个选中的点填一个非负整数,使得每个节点的数大于等于其子节点的数之和。根节点的数给定为 kk。求方案数。n105,k1018n\leq 10^5, k\leq 10^18,7s。

题解

Tags:

  • 多项式
  • 生成函数
  • 半在线卷积

fi(x)f_i(x) 为生成函数,考虑 ii 为根的子树,xx 的指数对应节点 ii 上的数。设 l,rl,r 分别为 ii 的左右儿子,有:

fi=1+flfr11x f_i=1+f_l \cdot f_r \cdot \frac{1}{1-x}

z=11xz=\frac{1}{1-x},考虑如何求出 fif_i 写成 zz 的多项式后的结果。

一个自然的想法是,每个点的状态由重儿子继承上来,再用轻儿子大小的复杂度合并上轻儿子的状态。但多项式乘法没办法做 O(min(n,m))O(\min(n,m))

我们考虑将 fif_i 用一列多项式 ai,1,,ai,ma_{i,1}, \dots, a_{i,m} 表示,要求 fi=(((ai,1+1)ai2+1)+1)ai,m+1f_i = (((a_{i,1}+1)a_{i_2}+1)\dots +1)a_{i,m}+1。用 ai,a_{i, \cdot}fif_i,只需要 O(nlog2n)O(n \log^2 n) 的时间做半在线卷积即可;而转移方程可以写成 fi=(fl)(zfr)+1f_i = (f_l) \cdot (z f_r) +1 的形式,即只需要在列表末尾添加 zfrz f_r。总复杂度为 O(nlog3n)O(n \log^3 n)

求出 f1(z)f_1(z) 后,要求 [xk]f1=i[xk](11x)iZi[x^k] f_1 = \sum_i [x^k] (\frac{1}{1-x})^i Z_i,只需求若干组合数即可。

CF1098E Fedya the Potter

2024-04-21

题意

给出序列 a1na_{1 \dots n},将 aa 的所有区间 gcd\gcd(共 (n+12)n+1\choose 2 个)排序得到序列 bb,将 bb 的所有区间和排序得到序列 cc,求 cc 的中位数。n5×104,ai105n\leq 5\times 10^4, a_i\leq 10^5

题解

Tags:

  • 最大公约数
  • 倍增
  • 类欧几里得算法

首先考虑序列 bb 的形式。在固定 aa 的子区间的左端点后,随着右端点的变化,gcd\gcd 至多变化 logai\log a_i 次,变化点可以倍增找到。因此我们可以得到至多 nlogain \log a_i 个不同的 gcd\gcd,因此序列 bb 的形式即为若干个值一致的连续段,不妨设 bb 中有 mm 个不同的数。

现在考虑第二部分。二分中位数 cc,此时我们需要求 c\leq c 的区间和的数量;抛开 r>l1r>l-1 的限制,把所有 (s[l],s[r])(s[l], s[r]) 放在平面上,我们需要查询 yx=cy-x=c 下方的点的数量。这些点可以被分成 m2m^2 的矩形区域,每个区域内都是以一定间隔均匀分布的;对于被直线切割到的矩形区域,我们需要用类欧几里得算法求点的数量;对于没被直线切割到的矩形区域,直接累加即可区域内的点即可。

示意图

CF1012F Passports

2024-04-22

题意

你有 PP 本护照,有 nn 个国家的旅游计划。每个国家你会在第 sis_i 天清晨到达,在第 si+li1s_i+l_i-1 天离开,这个国家的签证需要 tit_i 天来办理。

  • 你每到达一个国家时,你需要保证你带着的护照中有至少一个护照有这个国家的签证。
  • 如果你第 xx 天在起点,那你可以在当天中午把护照交给使领馆,第 x+tix+t_i 天中午无论你是否在起点都可以拿回护照(如果你在起点,你可以随即办理下一个国家的签证)。

问能否完成旅游计划。P2P\leq 2n22n\leq 22si,li,ti109s_i,l_i,t_i\leq 10^9

题解

Tags:

  • 状压 DP

先将国家按照到达时间排序。

护照和签证的限制整理后如下:

  • 开始办签证时,你必须在起点(没有旅游计划)。
  • 签证的办理时间早于到达时间。
  • 考虑一个护照,其每个签证的办理时间都不应与护照上的国家的旅游计划重叠。

状压 DP,设 f[S]f[S] 表示办理完 SS 集合内所有签证,最早拿回护照的时间。转移时枚举下一个国家,我们需要找到一个尽可能早的开始办理签证的时间:

  • 首先开始时间不能在旅游计划内。
  • 办理签证的总时段所相交的旅游计划集合,不能与 SS 有交。

我们从拿到签证的时间开始枚举,如果当前开始时间不合法,我们直接跳到下一次某个旅游计划结束的时间,再检查,直到找到一个合法的开始时间(或者找不到)。然后检查这个开始时间是否在对应旅游计划之前。

与开始时间和结束时间相关联的旅游计划可以双指针维护,同时也记到状态里,这样复杂度就(大概)是 O(2nn)O(2^n n) 的了(心虚)。

对于 P=1P=1 的情况即考察 f[{0,1,,n1}]f[\{0,1,\dots,n-1\}] 即可,对于 P=2P=2 的情况找到 f[S]f[S]f[{0,1,,n1}S]f[\{0,1,\dots,n-1\}\setminus S] 都合法的 SS 即可。

CF1023G Pisces

2024-04-27

题意

一棵树,边有长度。树上有很多鱼(怪),鱼每天可以沿着边走一单位长度。有 mm 条信息,每一条形如在第 dd 天有至少 ff 条鱼在节点 pp。求树上至少有多少鱼。n,m105n,m\leq 10^5。5s。

题解

Tags:

  • 图论
  • Dilworth 定理
  • 最大独立集
  • 数据结构优化 DP
  • 均摊复杂度
  • 启发式合并

对于每条信息,建 ff 个点,代表观察到 ff 条鱼。如果一个点能在相应时间内到达另一个点,则连一条有向边。从而问题转化为一个 DAG 的最小链覆盖。

最小链覆盖等于最长反链长度。不难发现选取了一个点在反链里,则把这个点所在的信息的所有点都选中肯定才优;同时本题的边是有传递性的,从而问题转化为:选取若干信息,其互相之间不能到达,使得被选出的总鱼数最大。

DP,设 f[i,l,r]f[i,l,r] 表示考虑点 ii 子树内的选法,不可能从选中的点到达在 (l,r)(l,r) 时段内的父亲、也不能从在 (l,r)(l,r) 时段内的父亲到达选中的点,选出来的节点的最大总价值。这个 DP 不太现实,但可以发现,我们可以把时段 (l,r)(l,r) 改成时刻 tt,只要这个时刻 tt 不与选中点互通的即可。

我们会对 f[i,t]f[i,t] 做几种操作:

  • 合并两个 f[i,t]f[i,t](对位相加)

  • 扩展一个 f[i,t]f[i,t] kk 的长度,得到 f[i,t]=maxtkjt+kf[i,j]f'[i,t] = \max_{t-k\leq j\leq t+k} f[i,j]

  • 合并完子树的 ff 后,我们要把 ii 节点上的观察算进来。不妨记 ii 到父亲的边边权为 ll。为此,我们有两种选择:不选择 ii 节点上的观察,这样得到 f[i,t]f[i,t] 扩展 ll 的结果;或者选择 ii 节点上的观察,得到 f[i,d+j]f[i,d]+f,j<lf'[i,d+j] \gets f[i,d]+f, |j|<l

    这个操作相当于我们将 ff 扩展 11 得到 ff',然后将【ff 单点加 ii 处各观察】和 ff'max\max,然后将 ff 扩展 l1l-1

我们使用数据结构维护差分数组。对于为正和为负的元素分别开两个 map 维护:

  • 合并操作直接启发式合并
  • 扩展操作会使得所有正元素左移、负元素右移,为此要打 tag。移动过程可能使得一个 ↓↑ 式的区间消失、两个元素合并为一个;为此我们维护一个优先队列,记录所有 ↓↑ 式的区间的(tag 为 00 时的)长度,当这个长度小于等于二倍 tag 时,这个区间就会消失.
  • 对于第三套操作,ff 扩展 11 得到 ff' 会使得某些位置增加,对 ff 单点加也会使得某些位置增加。我们对于所有要做单点加的地方,求这些位置通过扩展 11 会增加多少;扩展 11 后,我们再对这些位置单点加上【max(0,单点加产生的增量扩展 1 产生的增量)\max(0, \text{单点加产生的增量}-\text{扩展 1 产生的增量})】。

时间复杂度 O(nlog2n)O(n\log^2 n)(假装 n,kn,k 同阶)。

CF1039E Summer Oenothera Exhibition

2024-04-29

上来就分块,结果就只想出来 O(n5/3logn)O(n^{5/3} \log n) 空间复杂度还爆炸的做法,寄。

题意

给定长度为 nn 的序列,常数 ww,询问次数 qq。接下来 qq 组询问,每次给出一个常数 kik_i,求最少把序列分为多少段使得每段序列中数的极差不超过 wkiw-k_i,输出最小的段数。n,q105,w109n,q\leq 10^5, w\leq 10^9

题解

Tags:

  • 根号分治
  • LCT
  • ST 表

首先可以发现,当 wkiw-k_i 确定之后,可以每一段贪心尽可能地长。我们对每个点向后连边,连到自其开始、最长的极差不超过 wkiw-k_i 的区间的右端点的下一个点,由此得到一棵树。答案即为 11 的深度(减个常数)。

设定一个常数 BB,我们用数据结构维护 B\leq B 的跳跃,而 >B>B 的跳跃我们使用 ST 表来找。

将询问离线,按允许极差从小到大排序;提前预处理出来每个点能跳到的最远点的前 BB 个变化时刻。这样我们要做的操作为:

  • 更改一个点的父亲(也有可能直接断掉其与父亲的边)
  • 查询一个点所在子树的根,以及这个点的深度

查询时,先处理更新,然后从这个点开始,不断跳到根、然后用 ST 表跳一步,直到跳到 n+1n+1

考虑如何实现数据结构的部分。这部分类似于“弹飞绵羊”一题,官方题解选择分块维护,最后复杂度为 O(n5/3)O(n^{5/3}),而大部分洛谷上的题解选择 LCT,复杂度为 O(n3/2logn)O(n^{3/2} \log n)

由于 LCT 远慢于 ST 表,这个 BB 实际上要取到比 n\sqrt n 小上几倍。