【题解】P6397 题解

P6397 题解

思路分析

一道很基础的非整数的二分答案题。

非整数的二分答案有四个基本要素:左端点、右端点、合法判断、EPS(误差)。

首先我们确定 EPS 的值,题目建议我们至少保留四位小数,于是取 EPS 的值为 0.0001 即可。

其次我们确定左端点和右端点的初始值。左端点的初始值为 0(可以瞬间传),右端点的初始值为最大的 did_i,由于对于 1i<n1 \leq i \lt ndidi+1d_i \leq d_{i + 1}。所以右端点的初始值为 dnd_n

接着我们来写合法判断函数。记目前最远已传达距离为 tt,待验证的最短耗时为 xx。对于每个 did_i,分以下几种来判断与更新:

  • t+kt + k 小于 dixd_i-x。说明最大可传达距离都到达不了 did_i 的目前的可能的最前位置。不合法。
  • 否则,可以传达到该点。更新最远已传达距离为 t+kt + k
  • 如果 t+kt + k 大于 di+xd_i+x。说明最大可传达距离能到达 did_i 的目前的可能的最后位置。于是更新最远已传达距离为 di+xd_i+x,以便传得更远。
  • 如果都能传到,该方案合法。

直接进行求最小的二分答案即可。注意:因为精度问题,所以要开 long double。

关键代码

合法判断部分:

bool check(long double x)
{
    long double t = d[1] + x;
    for(int i = 2;i <= n;i++)
	{
	    if(t + k < (d[i] - x)) return false;
        if(t + k > (d[i] + x)) t = (d[i] + x);
        else t += k;
    }
    return true;
}

二分答案部分:

long double l = 0, r = d[n];
while(r - l > EPS)
{
	long double mid = (l + r) / 2.0;
	if(check(mid)) r = mid;
	else l = mid;
}
cout << fixed << setprecision(3) << r << endl;
posted @ 2022-11-19 14:48  邻补角-SSA  阅读(13)  评论(0)    收藏  举报  来源