1 条题解
-
0
题解
问题分析
在简单版本中,有 位老师和 个查询。我们需要计算在最优策略下,老师们抓住 David 所需的最少步数。
David 想最大化被抓的时间,老师们想最小化这个时间。由于所有人都能看到彼此的位置并最优行动,这是一个典型的追及问题。
核心思路
根据 David 相对于两位老师的位置,可以分为三种情况:
情况 1:David 在两位老师的左侧
即 David 的位置 满足 ( 是左边老师的初始位置)。
在这种情况下,David 的最佳策略是尽可能向左逃,最远可以到达格子 。左边的老师需要从 移动到 ,距离为 。右边的老师虽然也在追,但左边的老师会先抓住 David。
因此,所需时间为:
情况 2:David 在两位老师的右侧
即 David 的位置 满足 ( 是右边老师的初始位置)。
类似地,David 的最佳策略是尽可能向右逃,最远可以到达格子 。右边的老师需要从 移动到 ,距离为 。
因此,所需时间为:
情况 3:David 在两位老师之间
即 。
此时,David 的最佳策略是移动到两位老师的中间位置。由于两位老师从两侧同时逼近,David 可以停留在中间,使两位老师需要相同的步数才能同时到达。
两位老师之间的初始距离为 。当 David 位于正中间时,两位老师各需移动 步(如果距离为奇数,则中间有两个格子,选择任意一个均可)。
因此,所需时间为: $ans= \left\lfloor \frac{b_2 - b_1}{2} \right\rfloor $
注意:在代码中直接使用整数除法 即可,因为 C++ 整数除法会自动向下取整。
算法步骤
- 读入 (这里 )
- 读入两位老师的位置 并排序
- 读入 David 的位置
- 判断 David 相对于老师的位置:
- 如果 :输出
- 如果 :输出
- 否则:输出
标程解析
#include <bits/stdc++.h> using namespace std; int main() { ios_base::sync_with_stdio(false); cin.tie(0); cout.tie(0); int t; cin >> t; // 测试用例数 while (t--) { int n, m, q; cin >> n >> m >> q; // m=2, q=1 vector<int> a(m); for (int i = 0; i < m; i++) cin >> a[i]; sort(a.begin(), a.end()); // 确保 a[0] ≤ a[1] for (int i = 1; i <= q; i++) { int b; cin >> b; // 找到第一个大于等于 b 的老师位置 int k = upper_bound(a.begin(), a.end(), b) - a.begin(); if (k == 0) cout << a[0] - 1 << ' '; // 情况1: b < a[0] else if (k == m) cout << n - a[m - 1] << ' '; // 情况2: b > a[1] else cout << (a[k] - a[k - 1]) / 2 << ' '; // 情况3: a[0] < b < a[1] } cout << "\n"; } return 0; }代码说明:
upper_bound返回第一个大于 的老师位置, 表示该老师的索引- 若 ,说明 比所有老师都小(情况1)
- 若 ,说明 比所有老师都大(情况2)
- 否则, 在 和 之间(情况3)
复杂度分析
- 每个测试用例排序
- 每个查询
- 总复杂度 ,可以处理 的数据
示例验证
输入:
3 10 2 1 1 4 2 8 2 1 3 6 1 8 2 1 3 6 8处理过程:
-
第1个测试:
在 和 之间 → 向下取整得 -
第2个测试:
→ -
第3个测试:
→
输出:
1 2 2与示例输出一致。
- 1
信息
- ID
- 6192
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 2
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者