【NOIP2013模拟】穿越七色虹
Description
探险队员们跟随两位护法来到了七色虹前。七色虹,就是平面直角坐标系中赤橙黄绿青蓝紫七个半圆,第i座(1<=i<=7)半圆形彩虹的圆心是(xi,0),半径是ri,半圆上所有点的纵坐标均为非负数。探险队员可以看做一条竖直的、长度等于身高的线段,线段的底端纵坐标为0,最高的一位探险队员的身高为h。
现在探险队员们要从(0,0)到达(x0,0),穿越彩虹的过程中,探险队员的整个身体必须始终在至少一个半圆形彩虹的内部。由于彩虹的半径ri可能太小了,不足以满足这个条件,因此两位护法决定帮助他们把所有彩虹的半径都增大一个非负实数r。探险队员们想知道,r最小是多少呢?
Input
第一行两个实数h、x0,表示身高和目的地横坐标。
接下来七行每行两个实数xi、ri,表示七座半圆形彩虹的圆心和半径。
Output
输出最小的r,四舍五入保留2位小数。
Sample Input
4.0 36.0
0.0 4.0
6.0 4.0
12.0 4.0
18.0 4.0
24.0 4.0
30.0 4.0
36.0 4.0
Sample Output
1.00
Data Constraint
对于100%的数据,满足 0<=xi,x0<=10000;0< h<=100。
解题思路
二分答案,判断答案是否符合条件:
利用勾股定理判断线段是否覆盖(0,0)到(x0,0),注意精度,有可能有点超过x0的情况
Codes:
var a,b:array[0..7,1..2]of real;
i,j,tot:longint;
h,x0,l,r,m,ans:real;
function f(a,b:real):real;
begin
exit(sqrt(a*a-b*b));
end;
function pan:boolean;
var i,j,l:longint;
bool:boolean;
begin
if tot=0 then exit(false);
if b[1,1]>0 then exit(false); //判断是否覆盖前端
bool:=true;
for i:=tot downto 1 do
if b[i,2]>=x0 then
begin
bool:=false;
break;
end;
if bool then exit(false); //判断是否覆盖后端
l:=1;
for i:=1 to tot do
begin
if i>l then exit(false);
for j:=i+1 to tot do
if b[i,2]>=b[j,1] then
begin
if j>l then l:=j;
if l=tot then exit(true); //判断彩虹所覆盖范围是否依次相连
end;
end;
exit(true);
end;
begin
read(h,x0);
l:=0; r:=x0; ans:=x0;
for i:=1 to 7 do read(a[i,1],a[i,2]);
while l<r do //二分答案
begin
m:=trunc((l+r)*5000)/10000;
tot:=0;
for i:=1 to 7 do
if a[i,2]+m>=h then //加入半径增加后超过最高身高的彩虹
begin
inc(tot);
b[tot,1]:=a[i,1]-f(a[i,2]+m,h);
b[tot,2]:=a[i,1]+f(a[i,2]+m,h); //存入彩虹所管到的范围
end;
for i:=1 to tot-1 do
for j:=i+1 to tot do
if b[i,1]>b[j,1] then
begin
b[0]:=b[i];
b[i]:=b[j];
b[j]:=b[0];
end;
for i:=1 to tot do
if b[i,1]>x0 then break;
tot:=i-1; //将彩虹所管范围超过(0,0)到(x0,0)的排除
if pan then
begin
r:=m-0.001;
ans:=m;
end else
l:=m+0.001;
end;
writeln(ans:0:2);
end.