比赛链接:The 3rd Universal Cup. Stage 25: Hangzhou
VP 结果:两人四题铜牌,也算比较满意。
本文记录 A、E、H、K、M 五道题的题解。
总览
| 题目 | 状态 | 标签 |
|---|---|---|
| A | 赛时AC | 并查集 |
| E | 赛时AC | 贪心、排序 |
| H | 赛时AC | 构造、树 |
| K | 赛时AC | 贪心 |
| M | 赛后补题 | 数论、笛卡尔树 |
A. AUS
题意: 给定三个由小写字母组成的字符串 ,判断是否存在一种字符映射 ,使得 。每个字母映射为一个字母,不同字母可以映射到同一个字母。
思路:
先根据三个字符串的长度进行特判:
- 若 ,由于字符映射不会改变字符串长度,前两个字符串不可能映射为同一个字符串,答案为
NO。 - 否则,若 ,可以将所有字母映射为同一个字母,使前两个字符串相等;第三个字符串由于长度不同,一定与它们不同,答案为
YES。
接下来只需考虑三个字符串等长的情况。对 个字母建立并查集,逐位合并 和 。为了让前两个字符串映射后相等,这些对应位置上的字母必须映射为同一个字母;通过等价关系的传递,同一集合中的所有字母都必须映射为相同字母。
完成合并后,逐位检查 和 是否属于同一个集合:
- 若所有位置的两个字母都属于同一集合,那么任何满足 的映射都会使 ,无法区分,答案为
NO。 - 若存在一个位置的两个字母属于不同集合,就让不同集合映射为不同字母。集合至多有 个,因此这样的映射一定可以构造出来,并且该位置映射后不同,答案为
YES。
实现: 使用带路径压缩的并查集维护字母之间的等价关系。先扫描 合并对应字母,再扫描 ,判断是否存在所属集合不同的位置。
复杂度: 时间复杂度为 ,其中 为三个字符串的总长度,主要来自扫描字符串并合并、查询字母的所属集合。
E. Elevator II
题意: 有 个人等待乘坐电梯,第 个人要从 层到 层,其中 。电梯同时只能运送一个人,初始位于 层。向上移动一层消耗 单位电量,向下移动不耗电。求运送所有人的最小总耗电量,并输出一种最优的运送顺序。
思路:
每个人都必须从 被送到 ,所以载人上升的代价是固定的:
将它作为基准值后,只需要最小化额外的空载上升代价。
先按 从大到小排序,取排在第一位的乘客,其起点记为 。若初始楼层 ,就可以不花额外电量到达他的起点,送完后电梯到达最大的终点。接下来继续按终点从大到小运送:当前楼层不低于下一位乘客的终点,更不低于他的起点,因此接人只需下降,不会产生空载上升。此时额外代价为 ,总耗电量恰好为基准值,一定最优。
若 ,就先想办法到达不低于 的楼层,再执行上述顺序。在上升过程中,可以提前运送一些乘客,用他们的载人行程覆盖这段上升。这里的上升已经计入基准值,不需要额外付费。
为此,再将所有乘客按 从小到大排序,维护当前楼层 curf,初始为 。依次扫描乘客:
- 若 ,这位乘客不能帮助电梯继续上升,暂时跳过。
- 若当前仍有 ,就运送这位乘客。到达起点的额外代价为 ,随后电梯到达 ,令
curf更新为 ,记录他的编号并标记为已运送。 - 一旦 ,就不再提前运送乘客。将所有尚未运送的人按 从大到小接在答案后面即可,后续不会产生额外代价。
按起点递增扫描的原因是:若下一位能帮助上升的乘客满足 ,那么区间 内没有乘客行程可以帮助继续上升。此前扫描过的乘客,要么已经运送,要么终点不超过当前楼层;之后的乘客起点又都不小于 。这段空载上升因此无法避免。其余上升都由载人行程完成,所以算法只支付必要的额外代价。
实现: 保留两份乘客数组,分别按起点递增、终点递减排序。先计算基准值,再在起点递增的数组中构造提前运送的部分,用 vis[id] 标记已运送的乘客。最后扫描终点递减的数组,将未标记的编号依次加入答案。总耗电量使用 位整数保存。
复杂度: 时间复杂度为 ,主要来自对乘客按起点和终点排序。
H. Heavy-light Decomposition
题意: 给定 个节点和 条链,每条链由编号区间 内的节点按顺序组成。构造一棵有根树,使它的某一种轻重链剖分结果恰好是这些链,输出每个节点的父亲,根节点的父亲为 ;若无解,输出 IMPOSSIBLE。重儿子指子树大小最大的儿子,大小相同时可以任选一个。
思路:
链内的父子关系已经确定,只需要决定各条链的链头接到哪里。将链长定义为节点个数 ,按长度从大到小排序,记最长链长为 ,最短链长为 。
若只有一条链,直接将所有节点连成这条链即可。下面考虑至少两条链的情况。
先判断两种无解情况:
- 所有链的长度都相等。
- 最长链至少有两条,并且 。
其余情况分为两类构造。
最长链只有一条:
选这条最长链的第一个节点作为根 root,将其余所有链的链头都接到 root 上。
根在主链上的儿子,其子树大小为 ;其余儿子的子树就是各自整条链,大小至多为 。因此可以选择主链上的儿子作为重儿子。其他链内部都只有一个儿子,重边自然沿着原链延伸,剖分结果符合要求。
最长链至少有两条,且 :
任选一条最长链作为主链,将第一个节点记为 root,第二个节点记为 u2。把一条最短链的链头接到 u2 上,其余所有链的链头都接到 root 上。
这里必须接最短链,而不是再接一条最长链。构造后:
- 在
u2处,主链后继的子树大小为 ,接入的最短链子树大小为 ,所以仍可选择主链后继为重儿子。 - 在
root处,u2的子树大小为 ,其余儿子的子树大小至多为 ,所以仍可选择u2为重儿子。
其余节点没有额外分支,因此各条给定链都能保持为重链。子树大小相等时,选择主链方向即可。
实现: 按链长递减排序后,通过前两条链判断最长链是否唯一,通过首尾链判断最大、最小长度。链内统一令 ans[j] = j - 1,链头的父亲按上述分类设置,根的父亲保留为 。只有一条链时,直接输出 。
复杂度: 时间复杂度为 ,来自对 条链排序,以及构造、输出 个节点的父亲。
K. Kind of Bingo
题意: 给定一个 的网格和一个长度为 的操作序列。每次操作标记一个格子,每个格子恰好被标记一次。第一次出现某一整行都被标记时,已执行的操作次数记为 。可以交换序列中任意两个操作,至多交换 次,求 的最小值。
思路:
将每个格子被标记的时间按行分组。按操作顺序读入时,把当前时间加入对应行的数组,因此每行的标记时间天然递增,不需要额外排序。
先考虑让某一行尽早被全部标记。设这一行的标记时间依次为 。不交换时,要等到 才能完成这一行;至多交换 次,就可以把最后的至多 个标记操作换到前面。因此,当 时,关键就是这一行第 个标记的时间 。
同时,每次操作只能标记一个格子,完成一行至少需要 次操作,所以这一行最早完成的时间为
这个时间既是下界,也一定能够达到:令 ,此时这一行至少已有 个标记操作位于前 次操作中,缺少的标记至多有 个。由于 ,前 个位置中属于其他行的操作足够多,可以逐个与缺少的标记交换,从而在不超过 次交换后完成这一行。
枚举所有行,取第 个标记时间的最小值,再与 取最大值,就是最终答案。
若 ,则可以直接把任意一行的所有标记操作换到前 个位置,答案为 。
实现: 格子按行依次编号,从 开始。读到第 次操作标记编号为 的格子时,将 加入 pos[(x - 1) / m]。若 ,遍历每行的 pos[row][m - k - 1] 取最小值,最后与 取最大值。这里数组下标从 开始,所以第 个元素对应下标 。
复杂度: 时间复杂度为 ,主要来自读取并按行记录全部 次标记操作。
M. Make It Divisible
题意: 给定一个正整数序列 和整数 。若一个连续子数组中存在某个元素能够整除该子数组的所有元素,就称这个子数组是好的。要求给所有元素统一加上 后,每个连续子数组都是好的。求满足 的合法 的数量与总和。
思路:
首先特判所有元素都相等的情况。无论加上多少,所有元素仍然相等,每个区间都满足条件。因此 到 的所有整数都合法,数量为 ,总和为 。
下面考虑元素不全相等的情况。由于所有元素都是正数,一个区间中若有元素能整除所有元素,它一定就是区间最小值。因此题目等价于:每个区间的最小值加上 后,都能整除该区间内的每个元素加上 。
先用整个数组的条件缩小候选范围。记全局最小值为 ,则 必须整除所有 ,从而也必须整除任意两个相邻元素之差。令
于是 必须是 的正因数。分解 并枚举它的所有正因数 ,令 ,只保留 的候选。注意,因数 本身不是答案,减去全局最小值后才是候选 。
但整个数组满足条件,并不代表每个区间都满足。为此,对原数组建立小根笛卡尔树:节点的中序顺序与数组下标一致,父亲的值不大于儿子的值。统一加上 不改变元素之间的大小关系,所以所有候选都可以复用同一棵树。
对于每个候选 ,检查树上每条父子边。设父亲为 、儿子为 ,要求
只要存在一条边不满足,就舍弃该候选;若所有边都满足,就将 计入数量与总和。
正确性:
父子边条件是必要的:父亲与儿子两个下标之间的区间,最小值就是父亲的值,因此合法时父亲加 必须整除儿子加 。
它也是充分的:任意区间的最小值对应的节点,是该区间内所有节点的祖先。若每条父子边都满足整除关系,利用整除的传递性,这个最小值加 就能整除区间内每个元素加 。因此检查所有父子边,等价于检查所有区间。
实现: 先求最小值并特判全相等,再计算相邻差的 GCD。试除分解 后,通过 DFS 枚举各质因子的指数,生成所有因数。使用单调栈在线性时间内建立笛卡尔树,只需记录每个节点的父亲;栈顶的值严格大于当前值时弹栈,相等时保留。每个候选遍历所有非根节点,检查其与父亲的整除关系即可,无需显式建立儿子数组。数量、总和及相关运算使用 位整数。
复杂度: 时间复杂度为 ,其中 为 的正因数个数,三项分别来自数组排序、试除分解 ,以及对每个候选检查笛卡尔树的父子边。
如果这篇文章对你有帮助,欢迎分享给更多人!
部分信息可能已经过时
