• 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()的,不能只返回一个,这个要看代码规范了。

    代码:

    1. #include<bits/stdc++.h>
    2. using namespace std;
    3. #define inf 0x3f3f3f3f
    4. #define dou double
    5. #define EXP 0.0000001
    6. #define M 1000005
    7. int T;
    8. dou x;
    9. struct Node{
    10. dou x,v;
    11. }a,b;
    12. bool check(dou mid){
    13. return (mid+min(a.x,mid-a.x))/a.v>((x-mid)+min(x-b.x,b.x-mid))/b.v;
    14. }
    15. dou solve(){
    16. dou l=a.x,r=b.x;
    17. while(r-l>EXP){
    18. dou mid=(l+r)/2;
    19. if(check(mid)) r=mid;
    20. else l=mid;
    21. }
    22. 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
    23. }
    24. int main(){
    25. cin>>T;
    26. while(T--){
    27. cin>>x>>a.x>>a.v>>b.x>>b.v;
    28. if(a.x>b.x) swap(a,b);
    29. dou ans=(x+min(a.x,x-a.x))/a.v;
    30. ans=min(ans,(x+min(b.x,x-b.x))/b.v);
    31. ans=min(ans,max(b.x/b.v,(x-a.x)/a.v));
    32. printf("%.6lf\n",min(ans,solve()));
    33. }
    34. return 0;
    35. }

  • 相关阅读:
    JS--数组类型 Array 1
    java基础 --- 关键字 final、this、super、static
    《nginx》二、nginx反向代理
    L51.linux命令每日一练 -- 第八章 Linux磁盘与文件系统管理命令 -- mkfs和dumpe2fs
    web前端期末大作业——网页制作基础大二dw作业——动画漫展学习资料电影模板(6页)
    bert入门
    Redis集群
    解决若依Ruoyi 插入数据返回1,实现主键回填,返回主键ID
    苹果 AR/VR 头显售价 12000 元起,网友:“买来能干啥?”
    编程奇境:C++之旅,从新手村到ACM/OI算法竞赛大门(竞赛小魔法:万能头文件&加速)
  • 原文地址:https://blog.csdn.net/m0_58177653/article/details/125417916