1 条题解
-
0
「EGOI2021」瑞士铁路 题解
题目大意
在一条长度为 的铁路上,有 个隧道(每个隧道是单轨双向的),其余部分是双轨。有 趟从苏黎世到卢加诺的列车和 趟反方向的列车。所有列车速度均为 公里/分钟。
如果两列反向列车在隧道内部(严格内部,不包括端点)相遇,就会发生碰撞。要求判断是否会发生碰撞。
关键观察
1. 列车运动模型
设苏黎世为位置 ,卢加诺为位置 。
-
从苏黎世出发的列车 :
- 发车时间:
- 在时刻 的位置:()
-
从卢加诺出发的列车 :
- 发车时间:
- 在时刻 的位置:()
2. 相遇条件
两列反向列车 和 相遇时,它们位置相同且时间相同:
设相遇时间为 ,相遇位置为 ,则有:
$$\begin{cases} X = T - c_j \\ X = s - (T - d_k) \end{cases} $$解得:
3. 碰撞条件
碰撞发生的条件是:
- 两列车在隧道内相遇(严格内部)
- 即存在隧道 使得
算法设计
暴力解法(不可行)
直接枚举所有列车对和所有隧道,复杂度 ,在最大数据下会超时。
优化解法
核心思路:对于每对列车 ,计算相遇位置 ,然后快速判断 是否在某个隧道内部。
步骤:
- 预处理所有隧道区间
- 对每对列车 :
- 计算相遇位置
- 使用二分查找找到 可能属于的隧道
- 检查是否满足
复杂度:,可以接受()
实现细节
1. 浮点数问题
由于 可能很大,直接使用浮点数可能产生精度误差。
解决方案:
- 使用整数运算避免浮点数
- 检查 时,将不等式两边乘以 2:
2. 隧道查找优化
由于隧道按起始位置排序且互不相交,可以用二分查找快速定位:
// 找到第一个起始位置 <= X 的隧道 int l = 0, r = t - 1; while (l <= r) { int mid = (l + r) / 2; if (a[mid] <= X) { l = mid + 1; } else { r = mid - 1; } } // 检查隧道r是否包含X代码实现
#include <bits/stdc++.h> using namespace std; typedef long long ll; int main() { ios::sync_with_stdio(false); cin.tie(0); ll s; int t, m, n; cin >> s >> t >> m >> n; vector<ll> a(t), b(t); for (int i = 0; i < t; i++) cin >> a[i]; for (int i = 0; i < t; i++) cin >> b[i]; vector<ll> c(m), d(n); for (int i = 0; i < m; i++) cin >> c[i]; for (int i = 0; i < n; i++) cin >> d[i]; // 检查每对列车 for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { // 相遇位置 X = (c[i] - d[j] + s) / 2 // 使用整数运算避免浮点误差 ll numerator = c[i] - d[j] + s; // 二分查找可能的隧道 int l = 0, r = t - 1; int candidate = -1; while (l <= r) { int mid = (l + r) / 2; if (a[mid] * 2 <= numerator) { candidate = mid; l = mid + 1; } else { r = mid - 1; } } // 检查候选隧道 if (candidate != -1) { // 检查 a[candidate] < X < b[candidate] // 即 2*a[candidate] < numerator < 2*b[candidate] if (2 * a[candidate] < numerator && numerator < 2 * b[candidate]) { cout << "YES" << endl; return 0; } } // 检查下一个隧道(如果有) if (candidate + 1 < t) { if (2 * a[candidate + 1] < numerator && numerator < 2 * b[candidate + 1]) { cout << "YES" << endl; return 0; } } } } cout << "NO" << endl; return 0; }样例分析
样例2
s=1000, t=1, m=1, n=1 隧道: [600,700] c=[100], d=[400] 相遇位置: X = (100-400+1000)/2 = 350 350不在[600,700]内?等等,计算有误... 重新计算: X = (100-400+1000)/2 = 350 但列车1在时刻100从0出发,列车2在时刻400从1000出发 实际上它们在隧道[600,700]内相遇: 列车1到达600的时间: 100+600=700 列车2到达600的时间: 400+(1000-600)=800 不对... 正确计算: 设相遇时间T: T = (100+400+1000)/2 = 750 相遇位置X: X = 750-100 = 650 650在隧道[600,700]内部,所以碰撞!总结
本题的关键在于:
- 建立正确的列车运动模型
- 推导相遇时间和位置的公式
- 使用二分查找快速判断相遇点是否在隧道内部
- 注意整数运算避免精度误差
-
- 1
信息
- ID
- 4066
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 2
- 已通过
- 1
- 上传者