ICPC2021上海区域赛 D.Walker(二分分类讨论)

Posted K2MnO4

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ICPC2021上海区域赛 D.Walker(二分分类讨论)相关的知识,希望对你有一定的参考价值。

  • 题目:Walker
  • 题意:给出两个点a、b在一条线上的位置,并给出两个点的速度,问最少需要多少时间可以将整条线段覆盖(a、b方向任意)
  • 解析:
    1. a或b一人独自走完线段,两者最短时间t1
    2. a、b相向而行,对穿整条线段,两者最长时间t2
    3. 二分一个在a、b之间的点x,a负责区间[0, x],b负责区间[x, n]两者所花费的最大时间t3
    4. 最后比较t1、t2、t3大小
      重点1: 第一种和第二种的情况都挺好想的,主要想总结一下第三种情况,实际上第三种情况包含了非常多的情况,然后这里二分的思想是希望a与b完成相应区间覆盖所花的时间尽可能接近,因为最终是要完成整条线段的覆盖,类似于木桶效应;
      重点2: 其次,这里的二分有点卡精度,eps需要开到1e-7,看其他大佬写的题解发现,二分循环100次精度可以到达1e-30???,这样不容易被卡精度。
  • 代码1:
#include<bits/stdc++.h>
using namespace std;
int t;
double n, pa, pb, va, vb;
int main()
{
    cin >> t;
    while(t --)
    {
        double res = 1000000000;
        cin >> n >> pa >> va >> pb >> vb;
        if(pa > pb) swap(pa, pb), swap(va, vb); //始终让a在左侧
        res = min( (n + min(pa, n - pa)) / va, (n + min(pb, n - pb)) / vb); //a、b独自走完一条线段
        res = min(res, max( (n - pa) / va, pb / vb ) ); //a、b相向而行走到边界
        // 二分枚举一个点x, a、b负责覆盖x的左侧、右侧
        double l = pa, r = pb;
        while(r - l > 1e-7)
        {
            double mid = (l + r) / 2.0;
            double ta = min(pa + mid, 2 * mid - pa) / va; //先向左到起点后返回mid/先向右到mid再返回起点
            double tb = min(n + pb - 2 * mid, 2 * n - pb - mid) / vb;
            res = min(res, max(ta, tb)); //类似木桶效应
            if(ta > tb) r = mid; //缩小a的时间
            else l = mid; //增加a的时间
        }
        printf("%.6lf\\n", res);
    }
    return 0;
}

  • 代码2(控制精度方法):
#include<bits/stdc++.h>
using namespace std;
int t;
double n, pa, pb, va, vb;
int main()
{
    cin >> t;
    while(t --)
    {
        double res = 1000000000;
        cin >> n >> pa >> va >> pb >> vb;
        if(pa > pb) swap(pa, pb), swap(va, vb); //始终让a在左侧
        res = min( (n + min(pa, n - pa)) / va, (n + min(pb, n - pb)) / vb); //a、b独自走完一条线段
        res = min(res, max( (n - pa) / va, pb / vb ) ); //a、b相向而行走到边界
        // 二分枚举一个点x, a、b负责覆盖x的左侧、右侧
        double l = pa, r = pb;
        for(int i = 1; i <= 100; i++)
        {
            double mid = (l + r) / 2.0;
            double ta = min(pa + mid, 2 * mid - pa) / va; //先向左到起点后返回mid/先向右到mid再返回起点
            double tb = min(n + pb - 2 * mid, 2 * n - pb - mid) / vb;
            res = min(res, max(ta, tb)); //类似木桶效应
            if(ta > tb) r = mid; //缩小a的时间
            else l = mid; //增加a的时间
        }
        printf("%.6lf\\n", res);
    }
    return 0;
}

以上是关于ICPC2021上海区域赛 D.Walker(二分分类讨论)的主要内容,如果未能解决你的问题,请参考以下文章

ICPC2021上海区域赛 B.Mine Sweeper II(思维构造)

ICPC2021南京区域赛 L.Let's Play Curling(二分思维构造)

2019上海icpc区域赛补题

(ICPC)亚洲区域赛上海 M.Gitignore(模拟,map)

Digit sum (第 44 届 ACM/ICPC 亚洲区域赛(上海)网络赛)进制预处理水题

(ICPC)亚洲区域赛(上海)Mine Sweeper II(思维)