专栏文章
题解:CF2172B Buses
CF2172B题解参与者 1已保存评论 0
文章操作
快速查看文章及其快照的属性,并进行相关操作。
- 当前评论
- 0 条
- 当前快照
- 1 份
- 快照标识符
- @min2qhty
- 此快照首次捕获于
- 2025/12/01 19:36 3 个月前
- 此快照最后确认于
- 2025/12/01 19:36 3 个月前
结论题。
题解中变量名与题面中有不同:。
翻译(简化)
一条路长 。有 辆均以 的速度向右匀速运动(即每秒向右走 单位长度)的列车,均在零时刻发车,第 辆发自 终于 。(位置 表示距路左端点 。)
有 人,第 个人从位置 出发到路右端点(位置 ),可以 的速度行走,亦可乘车:若某时刻与某列车位置相同,则可上车;若已上车,可随时下车,但车到终点必须下车。(可不在整数时刻与位置上车。)
求出每个人到达终点的最短时间。以小数输出,要求相对相对误差或绝对误差小于 。
数据范围:。
题解
试试新渲染特性,以效 CF 题解之风。(注:建议按照数字 0、1、2、3、4 的顺序先点开提示,独立思考片刻。解答是该提示对应的步骤,解答 0、1、2、3、4 顺序连接构成完整的题解)
提示 0.0
所有的车速度一样。
提示 0.1
对每个人分析,他能上哪些列车?
解答 0
所有起点在位置 之左(含 ),终点位置在 之右的列车都可搭乘。
即若 ,则第 个人可搭乘列车 。
由于所有车平行运动(速度一样),所以不可能出现超车现象(乘一辆车追上另一辆车),于是在 之右的列车,是不可能出现乘一辆车追上的。当然走路追就更不可能了。()
所以只有起点在位置 之左(含 )的列车可搭乘。
提示 1.0
车不等人,只会按照既定轨迹准时达到终点。
提示 1.1
结论:最多上一辆列车。想想为什么?
解答 1
假设要上两辆车,不如只上右边那辆车。因为无论上不上前一辆车,都能上后一辆车(所有在 前的皆可上)。而无论是否上前一辆,到达终点的时间不变。
提示 2
求出若乘车 ,到达右端点 的时间。
解答 2
显然坐车应该坐到终点,因为走路不如坐车快。
车走了 的路程,由速度公式,在 时刻到达终点。
之后走路,从 到 ,用时 。
相加,通分,总用时 。
解答 3
在所有能坐上的车中,应选取一个用时最短的。
(易错点:还可以纯走路。用时 。不过这个到输出结果时取最小值就好了。)
所以题目转换为了:有 个询问,每个询问给出 ,要在所有 的 中求出 最小值。
提示 4.0
是否可以去掉?
解答 4.0
如果 ,那么坐了这辆车,不仅用了时间,而且还退后了,肯定不优,会在取最小值时自动舍去,所以可以忽略 的条件。
提示 4.1
去掉这个条件后,越往右,能坐的车就越多。
提示 4.2
很自然地想到,给每个位置都记录最小乘车时间就好了。但这样会超时:。
提示 4.3
记录必要的即可。
解答 4.3
显然,只有 所在位置,才有可能导致能乘的车改变。所以只需要对于每个 ,记录从 出发最小乘车时间(不考虑纯走路所用的最短时间)。
遂按 排序,从左到右依次求最小乘车时间。
设 表示从 到 这段区间内出发的点,最小乘车时间。可推出状态转移方程:。(注: 是因为在 左边的乘不到车,这样与纯走路取 时自动舍去。)
然后对每个人,二分查找最大的 使 即可。(离线排序再双指针亦可。)
代码(C++)
为运算方便,将时间都乘以了 以变成整数。最后输出时再除 。
CPP#include<iostream>
#include<algorithm>
using namespace std;
struct xyq{
int l,r;
}a[1000005];
struct rule{ //特殊比较方式。为了按照 $l$ 排序。
bool operator()(const xyq &s0,const xyq &s1){
return s0.l<s1.l;
}
};
long long zyl[1000005];
int main(){
int n,m,l,i,j;
long long v0,v1;
xyq tkr;
cin>>n>>m>>l>>v0>>v1;
for(i=0;i<n;i++){
scanf("%d %d",&a[i].l,&a[i].r);
}
sort(a,a+n,rule());
zyl[0]=2012345678987654321ll;
for(i=1;i<=n;i++){
zyl[i]=min(zyl[i-1],(a[i-1].r-a[i-1].l)*v1+(l-a[i-1].r)*v0);
}
for(i=0;i<m;i++){
scanf("%d",&tkr.l);
//下面一行,zyl[upper_bound(a,a+n,tkr,rule())-a] 是指最小的乘车时间,(l-tkr.l)*v0 是纯走路所用时间,两者取 min。
printf("%.8f\n",(double)min(zyl[upper_bound(a,a+n,tkr,rule())-a],(l-tkr.l)*v0)/(v0*v1)); //这里 upper_bound 是返回大于 tkr 的最小位置,返回值是一个指针,所以减去起始位置。大于 tkr 的前一个位置就是小于 tkr 的最大位置。由于 a 数组从 0 开始编号,本身就左移了 1 位,就不用再减一了。
}
return 0;
}
易错点:浮点数输出
相关推荐
评论
共 0 条评论,欢迎与作者交流。
正在加载评论...