【笔记】【掏空脑子】WC2021-day2-集训队作业选讲
[WC2021day2] 集训队作业题选讲
_by 蒋明润
[IOI2020day1T1]plants/P6829 [IOI2020]植物比较
拓扑排序找读数为零
线段树区间减操作删除
引理1:通过已知信息可以唯一确定任意两棵
距离小于𝑘的植物高度的大小关系
倍增跳\(left\)和\(right\)
[2020国集作业第89题]01 on Tree
解题过程
– 思路:直接解决这个不容易,可以考虑解决一
个更强的问题:每个节点上写的是一个非空01
序列。
– 设𝑎[𝑖]为节点𝑖上的序列中0的个数,𝑏[𝑖]为节点𝑖上
的序列中1的个数。
– 设排成的序列为𝑝,考虑交换𝑝[𝑖]和𝑝[𝑖 + 1]
考虑满足𝑏 [𝑖] /𝑎[𝑖]最小的非根节点𝑖,我们可以通过
交换将节点𝑖不断向前移动直到移动到𝑖的父节点后
面一个位置,且移动过程中答案不会变劣。所以必
定存在一个最优解,满足𝑖在𝑖的父节点后面一个位
置。所以可以将𝑖和𝑖的父节点合并,合并后的01序
列为两个01序列拼在一起。反复执行该操作直到树
只剩下根节点,此时根节点上的01序列就是最后的
01序列。
– 用堆维护𝑏[𝑖] /𝑎[𝑖]最小的非根节点,用并查集维护
合并之后每个节点的父节点,可以做到时间复杂度
Ο(𝑛𝑙𝑜𝑔𝑛)
[2020国集作业第123题] Painting Edges(https://codeforces.com/contest/576/problem/E)
线段树分治维护边出现的时间
带权并查集判断是否是二分图
[2020国集作业第36题] Restoring Map (https://codeforces.com/contest/566/problem/E)
使劲分类讨论,细节
\(bitset\)优化集合求交,O(\(n^3 / w\))
[2020国集作业第37]Complete Compress (https://atcoder.jp/contests/agc034/tasks/agc034_e)/(https://www.luogu.com.cn/problem/AT4995)
枚举根结点
记𝑓[𝑢]为只考虑子树𝑢时所有棋子的深度和在操
作后能达到的最小值,𝑔[𝑢]为子树𝑢中的所有棋
子操作前的深度和,𝑠𝑖𝑧𝑒[𝑢]表示子树𝑢中的棋
子个数。𝑔[𝑢]和𝑠𝑖𝑧𝑒[𝑢]求法显然,考虑怎么求
𝑓[𝑢]。
从𝑓 𝑢 = 𝑔 𝑢 = 0开始,不断加入子树。在加
入子树𝑣时,令
– 𝑓 𝑢 ≔
𝑓 𝑢 − 𝑔 𝑣 + 𝑠𝑖𝑧𝑒 𝑣 (𝑓 𝑢 > 𝑔 𝑣 + 𝑠𝑖𝑧𝑒 𝑣 )
𝑓 𝑣 + 𝑠𝑖𝑧𝑒 𝑣 − 𝑔 𝑢 (𝑓 𝑣 + 𝑠𝑖𝑧𝑒 𝑣 > 𝑔 𝑢 )
𝑔 𝑢 + 𝑔 𝑣 + 𝑠𝑖𝑧𝑒[𝑣] 𝑚𝑜𝑑 2 𝑜𝑡ℎ𝑒𝑟𝑤𝑖𝑠𝑒
– 然后更新𝑔[𝑢]。
时间复杂度可以优化到O(n)
[2020国集作业第38题] Shopping (https://atcoder.jp/contests/agc022/tasks/agc022_d)
前缀和
括号序列
– 考虑计算火车到两端的最少次数,则答案为这个最
少次数×𝐿。
– 由于𝑡i > 2𝐿时火车到两端的次数为将𝑡i视为𝑡i − 2𝐿
时到两端的次数+2,所以下面只考虑𝑡i ≤ 2𝐿的情
况。
– 我们将Yui进入一个车站(进入一个购物中心购物
或者到达端点然后返回)的方式分成三类:
• 方式(1):从左边进入,从左边离开。
• 方式(2):从右边进入,从右边离开(包括回到原点不
离开)。
• 方式(3):从左边进入,从右边离开或者从右边进入,
从左边离开。
– 如果给出进入每个车站的方式,怎么判断能否做到
按给出的进入的方式进入每个车站?
• 如果是按方式(1)进入,在这个位置记录上−𝟏;如果
是按方式(2)进入,记录上𝟏;按方式(3)进入则记录
𝟎。则能够按要求进入每个车站,当且仅当所有位置记录
的数的和为𝟎,且所有非空、非全集的前缀和为正。
– 证明如下:
• 对于一个位置,显然Yui从左边经过这个位置的次数
等于这个位置左边的数的和。
• 如果所有数的和非零,则经过一个坐标𝐿右边的位置
的次数非零,这是不可能的。
• 如果存在一个非空,非全集的前缀和非正,那么存
在一个位置在原点右侧,从左边经过它的次数非正,
并且在这个位置右侧还有需要进入的车站,这是不
可能的。
– 证明(续):
• 而如果所有位置记录的数的和为0,且所有非空、非
全集的前缀和为正,则将1看成左括号,−1看成右
括号(0只需要Yui的路线经过这个车站即可),对
应一个合法的括号序列,且最后一个右括号和第一
个左括号对应。那么原点→第一个右括号→第一个
右括号对应的左括号→第二个右括号→第二个右括
号对应的左括号→ ⋯ →最后一个右括号→最后一个
右括号对应的左括号(原点)就是合法的路径。''
– 下面考虑如何解决原问题
– 显然能上火车的时候一定上火车。由于𝑡i ≤ 2𝐿,所以在购物
中心购物时,火车到达端点的次数(下称“代价”)只会是
1或2。
– 如果从左边进入和从右边进入代价都是1,那么可以自由决
定以方式(1)进入还是以方式(2)进入。
– 如果从左边进入代价是1,从右边进入代价是2,那么显然从
左边进入不会更劣,也就是只能以方式(1)进入。
– 如果从左边进入代价是2,从右边进入代价是1,那么显然从
右边进入不会更劣,也就是只能以方式(2)进入。
– 如果从左边进入和从右边进入代价都是2,那么只能以方式
(3)进入。
– 现在问题转换成了:给定一个包含问号的括号
序列,要求确定问号的取值,然后在两边添加
若干个括号,使得括号序列合法,且第一个左
括号和最后一个右括号对应,要求括号数量最
少。
– 显然前面一部分问号变成左括号,后面一部分
变成右括号。枚举哪些变成左括号,可以通过
预处理前后缀和做到𝑂(1)判断添加的括号的数
量。总复杂度𝑂(𝑛)。
[2020国集作业第152题] Donation (https://atcoder.jp/contests/arc098/tasks/arc098_d)
– 正向考虑这个过程较难处理(虽然也可以处
理),我们逆向考虑这个过程。
– 问题等价于:你可以以任意非负初始钱数从任
意一个点出发,然后沿着图中任意边行走,当
你离开一个点𝑢(包括最终停止在点𝑢)时,需
保证此时的钱数不小于𝑎b,当你位于点𝑢时,
可以“捐赠” 一次使钱数增加𝑏b,要求给每个
点“捐赠”一次,最终的钱数最少。
– 每一个点都会捐赠一次,所以最终钱数最少等
价于初始钱数最少。
– 显然对于每一个点会在第一次访问这个点时
“捐赠”。
– 令𝑐b = max(𝑎b − 𝑏b, 0),则进入点𝑢时只需保
证钱数不小于𝑐b(即“捐赠”一次后不小于
𝑎b)。
– 按照𝑐b从小到大的顺序加入每一个点,用并查
集维护连通块,可以得到一个树形结构,子树
𝑢代表加入𝑢时形成的连通块。
– 不难证明在确定初始位置和钱数之后,可以以
任意顺序访问可以访问的节点。
– 当访问到点𝑢时,子树𝑢中的所有点的𝑐值都不
超过𝑐b,可以访问。
– 访问完子树𝑢后,能到达的未访问点中𝑐值最小
的点为𝑢的父节点𝑓,此时访问𝑓必然可行,否
则无解。
– 访问节点𝑓后可以访问子树𝑓,然后访问𝑓的父
节点,以此类推
– 𝑑𝑝[𝑢]表示访问子树𝑢需要的最少钱数,转移时
枚举访问𝑢之前先访问了哪个子树。
– DP的时间复杂度为𝑂(𝑛),时间复杂度瓶颈为排
序的𝑂(𝑛𝑙𝑜𝑔𝑛)
[2020国集作业第150题] Mr. Kitayuta vs. Bamboos (https://codeforces.com/contest/506/problem/C)
二分答案
堆维护
– 首先二分答案,问题转化为判断能否使𝑚天后
所有竹子高度均不超过𝑋。
– 逆向考虑这个过程,记ℎ′表示如果在原问题中
此时竹子的高度超过ℎ′,则竹子最终的高度会
超过𝑋
– 则在逆向过程中,ℎ′的初始值为𝑋,在每天开始
时ℎ′会减少𝑎i,每天可以做𝑘次操作,每次操作
可以选择一棵竹子将ℎ′增加𝑝(不能在ℎ′减小至
负数后增加),要求𝑚天后ℎ′不小于ℎi
– 最优决策为选择(如果不操作)ℎ′减小至不合
法(减小至负数或者过程结束后小于ℎi)的时
间最早的竹子进行操作。
– 可以用堆维护,时间复杂度为𝑂((𝑛 +
𝑘𝑚)𝑙𝑜𝑔𝑛),算上二分的时间复杂度后为
𝑂( 𝑛 + 𝑘𝑚 𝑙𝑜𝑔𝑛 𝑙𝑜𝑔𝐻)