1 条题解
-
0
#5436. 「OOI 2016 Day 2」蝙蝠侠归来 题解
问题分析
我们需要在区间 中找到一对下标 ,满足:
- 最大化
如果没有满足条件的对,输出
-1 -1。关键观察
1. 问题转化
这是一个区间最大跨度对查询问题,但带有高度约束 。
2. 候选对的性质
对于最优解 :
- 应该是 中小于 且最左边的元素
- 应该是 中大于 且最右边的元素
3. 分治思路
考虑分治解决:对于区间 ,最优解要么完全在左半区间 ,要么完全在右半区间 ,要么跨越中点。
跨越中点的候选解:
- 对每个右半区的 ,在左半区找到满足 且 最小的位置
- 对每个左半区的 ,在右半区找到满足 且 最大的位置
算法框架
1. 分治预处理
使用分治算法预处理所有可能的候选对:
def solve(L, R): if L == R: return [] mid = (L + R) // 2 # 递归解决左右子问题 left_pairs = solve(L, mid) right_pairs = solve(mid+1, R) # 处理跨越中点的候选对 cross_pairs = [] # 情况1:对每个右半区的q,找左半区最小的p满足h_p < h_q # 情况2:对每个左半区的p,找右半区最大的q满足h_q > h_p return merge(left_pairs, right_pairs, cross_pairs)2. 候选对存储
对于每个区间 ,我们存储:
- 所有可能成为最优解的候选对
- 这些候选对按某种顺序组织以便快速查询
3. 查询处理
对于查询 :
- 找到完全包含 的线段树节点
- 在这些节点的候选对中寻找满足 且 最大的对
优化技巧
1. 单调性利用
在分治的跨越中点步骤中,可以使用单调栈来高效找到候选对:
- 从左往右扫描左半区,维护高度递减的单调栈
- 从右往左扫描右半区,维护高度递增的单调栈
2. 候选对剪枝
对于候选对 ,如果存在 满足 且 且 ,那么 可以被剪枝。
3. 线段树构建
将整个数组建立线段树,每个节点存储该区间内的所有候选对(经过剪枝的)。
复杂度分析
- 预处理:,分治过程中每个区间需要 时间处理
- 存储空间:,每个元素出现在 个区间中
- 单次查询:,需要在 个节点中分别二分查找
- 1
信息
- ID
- 4964
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者