20年上海站D题Walker(二分,简洁)

题目描述

As a world-famous traveler, Prof. Pang's research interest is to travel as many places as possible in his life.

We have a segment [0,n]{[0, n]}[0,n]. There are two travelers on it. The first one is on position p1p_1p1​ with velocity v1v_1v1​ (which means s/he can walk v1v_1v1​ unit on the segment per second). The second one is on position p2p_2p2​ with velocity v2v_2v2​.

From their respective beginning points, travelers can walk on the segment. They cannot walk outside the segment. Whenever they want to change their direction, they can turn around immediately.

Please help Prof. Pang to calculate the minimum possible time by which every position of the segment is passed by at least one traveler.

输入描述:

The first line contains one integer test (1≤test≤10000)test~(1\le test\le 10000)test (1≤test≤10000) -- the number of test cases.

The i-th of the next test lines contains five numbers n,p1,i,v1,i,p2,i,v2,in, p_{1, i}, v_{1, i}, p_{2, i}, v_{2, i}n,p1,i​,v1,i​,p2,i​,v2,i​ (0<n≤100000 < n \le 100000<n≤10000, 0≤p1,i,p2,i≤n0\le p_{1, i},p_{2, i} \le n0≤p1,i​,p2,i​≤n, 0.001≤v1,i,v2,i≤10000.001 \le v_{1, i},v_{2, i} \le 10000.001≤v1,i​,v2,i​≤1000). All numbers have at most 3 digits after the decimal point.

输出描述:

For each test case, we should output one number -- the minimum time that every position of the segment is passed by at least one traveler.

Your answer is considered correct if its absolute or relative error does not exceed 10−610^{-6}10−6.

输入

2
10000.0 1.0 0.001 9999.0 0.001
4306.063 4079.874 0.607 1033.423 0.847

输出

5001000.0000000000
3827.8370013755

题意:0-n的一维坐标上,给任意两点的位置和速度,他们可以任何时候去任何方向,求这两个点共同走完所有地方需要最少的时间。

思路:

首先判断是否是前一个位置更小,不是的话swap翻转一下,前面的为a,后面为b

做题思路不是特别难,分四中情况:

1.只用a或者b,答案就是:(x+min(a.x,x-a.x))/a.v,和(x+min(b.x,x-b.x))/b.v),因为a或者b可以选择先到达左端点还是右端点

2.a和b交叉走,且交叉一直走。答案就是:max(b.x/b.v,(x-a.x)/a.v),最大使用时间即是答案。

隔壁拿的图,侵删

3.左边由a来走,右边由b来走。中间的点为mid,则mid一定在a和b起始点之间,因为一旦a向右超过了b起始点,那么b就不用往右走了,b就没用了,属于第一种情况了。

侵删

 这种就是mid左边是a来走,右边是b来走

a走的最短路径就是:mid+min(a.x,mid-a.x)

b走的最短路径就是:l-mid+min(n-b.x,b.x-mid)

而且是小数的答案,两边的最大值是答案,一定是左右使用时间相同时最优,这个过程可以二分。

这题还有一点很重要,就是精度问题,以至于有的题解有100次二分的for

但如我下面的代码,没有long double,没有1e-10,没有多小数位输出

这题的精度卡的是那个二分返回的结果:return max(l/a.v+(min(a.x,l-a.x))/a.v,((x-l)+min(x-b.x,b.x-l))/b.v);

一定是max()的,不能只返回一个,这个要看代码规范了。

代码:

#include<bits/stdc++.h>
using namespace std;
#define inf 0x3f3f3f3f
#define dou double
#define EXP 0.0000001
#define M 1000005
int T;
dou x;
struct Node{
    dou x,v;
}a,b;
bool check(dou mid){
    return (mid+min(a.x,mid-a.x))/a.v>((x-mid)+min(x-b.x,b.x-mid))/b.v;
}
dou solve(){
    dou l=a.x,r=b.x;
    while(r-l>EXP){
        dou mid=(l+r)/2;
        if(check(mid)) r=mid;
        else l=mid;
    }
    return max(l/a.v+(min(a.x,l-a.x))/a.v,((x-l)+min(x-b.x,b.x-l))/b.v);        //这里一定是max,只返回左边时间或右边时间会WA
}
int main(){
    cin>>T;
    while(T--){
        cin>>x>>a.x>>a.v>>b.x>>b.v;
        if(a.x>b.x) swap(a,b);
        dou ans=(x+min(a.x,x-a.x))/a.v;
        ans=min(ans,(x+min(b.x,x-b.x))/b.v);
        ans=min(ans,max(b.x/b.v,(x-a.x)/a.v));
        printf("%.6lf\n",min(ans,solve()));
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/m0_58177653/article/details/125417916