2024解题报告
2024.3.4
A.「ROI 2017 Day 2」学习轨迹
题面:
给定两个二元组序列 \(\text{A}\) 和 \(\text{B}\),每个二元组表示这个位置的数的编号与价值。
可以对于两个序列各选取一个区间(可以为空),使得两个区间中的数的编号不重复出现,要求在满足该条件的情况下,区间的价值和最大。
思路
首先来考虑最劣解是什么情况,可以发现最劣的情况是全选其中一个序列,另一个序列不选。
所以在分别进行区间选取的时候,一定有一个序列选取的区间里值的总和大于该序列中和的一半。
因为如果两个序列选取区间的取值和都不足该序列总和的一半,全选某个区间一定是更优的。
那先假定序列 \(\text{A}\) 选取的和超过一半,那其实可以得到一个必选的点。
假设这个点为 \(\text{p}\),那么 \(\text{p}\) 需要满足的条件就是 \(\text{p}\) 的前缀和大于总和的一半, \(\text{p}\) 的后缀和大于总和的一半,这样,不管怎么选,\(\text{p}\) 一定会被选中,具体地说,\(\text{p}\) 就是前缀和第一个大于总和的一半的位置。
接下来考虑另一个序列 \(\text{B}\) 对序列 \(\text{A}\) 的影响。
可以发现,如果每次选择一个 \(\text{B}\) 中的值,如果这个值在 \(\text{A}\) 中出现过,那么一定可以确定一个 \(\text{A}\) 所选取的区间的左端点大于某个数或者右端点小于某个数。
原因是显然的,因为在 \(\text{B}\) 中选了的数在这 \(\text{A}\) 中一定不能再选了,所以自然可以为 \(\text{A}\) 确定一个范围。
性质的分析差不多结束了,那么接下来就可以考虑如何求解了。
可以考虑枚举 \(\text{B}\) 序列选择的右端点,然后使用个什么东西维护对于该右端点的最大值。
但具体该怎么维护呢?
想到 \(\text{A}\) 序列中存在一个必须选的点,那么可以根据类似分治的思想,以这个点为界限,分成左右两个部分考虑。
对于每个新枚举到的 \(\text{B}\) 序列中的数,如果在 \(\text{p}\) 的左边,那么在这个数之前的都要删除,如果在 \(\text{p}\) 的右边,那么在这个数之后的都要删除。
这个单调性显然可以使用一个递增的单调栈进行维护,每次加入的时候,先把栈中比这个数位置靠前或者靠后的贡献全部删掉,然后加入这个点的贡献。
贡献的改变可以使用一颗线段树进行维护,注意有点小技巧,在维护的过程中,不单只维护 \(\text{A}\) 的值,同时需要把 \(\text{B}\) 的区间贡献通过前缀和拆成两部分,把减掉的部分加入线段树中一起维护,加的那部分在枚举的时候直接加上就行,这样才能保证和是最优的。(建议结合代码理解)
最后把 \(\text{A}\),\(\text{B}\) 序列交换再处理一遍即可。
时间复杂度: \(O(n \log n)\)

浙公网安备 33010602011771号