Description
探险队员们跟随两位护法来到了七色虹前。七色虹,就是平面直角坐标系中赤橙黄绿青蓝紫七个半圆,第i座(1<=i<=7)半圆形彩虹的圆心是(xi,0),半径是ri,半圆上所有点的纵坐标均为非负数。探险队员可以看做一条竖直的、长度等于身高的线段,线段的底端纵坐标为0,最高的一位探险队员的身高为h。
现在探险队员们要从(0,0)到达(x0,0),穿越彩虹的过程中,探险队员的整个身体必须始终在至少一个半圆形彩虹的内部。由于彩虹的半径ri可能太小了,不足以满足这个条件,因此两位护法决定帮助他们把所有彩虹的半径都增大一个非负实数r。探险队员们想知道,r最小是多少呢?
看完满是实数的样例,心中有点慌
于是选择了高度优先搜索,即二分答案,验证可行性
至于实数的问题,强行卡
把精度保留两位小数(即将所有数字乘以100)
然而,这是20分做法
100分做法!!
Water:
强行暴力枚举每一个点
勾股求出点和7个圆心的距离,更新答案
那么问题来了,实数点枚举啥么玩意儿?
又要卡精度了…
由于只用考虑极端情况(即探险队员头顶)
那么这些点应都是(H,i)的形式。
每次i+0.002卡卡精度,就能273ms水过
正解:
0ms
二分+勾股定理+线段覆盖
用勾股求出每个圆可以覆盖的区间
也就是求图中黄色区域
然后更新答案即可。
Tips:
水法不必排序
正解记得是要的
自行思考Why
各取所需吧
Code:
water
自认为还是很优美的,水法最快。
const
maxh=100;
maxXi=10000;
var
ans,min,tmp:real;
h,x0,now:real;
i,j,l:longint;
lastl,lastr:real;
left,right,mid:real;
a:array[0..8,0..1] of real;
function max(a,b:real):real;
begin
if a>b then exit(a) else exit(b);
end;
function dis(a,b:real):real;
begin
exit(sqrt(abs(sqr(a)+sqr(b))));
end;
begin
readln(h,x0);
for i:=1 to 7 do readln(a[i,1],a[i,0]);
now:=0;
while(now<=x0)do
begin
min:=maxlongint;
for i:=1 to 7 do
begin
tmp:=dis(h,a[i,1]-now)-a[i,0];
if tmp<min then min:=tmp;
end;
ans:=max(min,ans);
now:=now+0.002;
end;
writeln(ans:0:2);
close(input);close(output);
end.
正解:
毕竟是正解啊!
var
x,r:array[0..7] of extended;
h,x0,ans,l1,r1,mid:extended;
i,j:longint;
p:boolean;
function min(x,y:extended):extended;
begin
if x<y then exit(x) else exit(y);
end;
function pd(len:extended):boolean;
var
i,s:longint;
t:extended;
begin
for i:=2 to 7 do
begin
if x[i]>x0 then break;
if sqr(r[i-1]+len)<h*h then exit(false);
if sqr(r[i]+len)<h*h then exit(false);
t:=sqrt(sqr(r[i-1]+len)-h*h);
t:=t+sqrt(sqr(r[i]+len)-h*h);
if t<x[i]-x[i-1] then exit(false);
end;
s:=i-1;p:=false;
if x[i]<=x0 then inc(s);
for i:=1 to s do
begin
t:=sqrt(sqr(r[i]+len)-h*h);
if t>=x0-x[i] then p:=true;
end;
for i:=s+1 to 7 do
begin
if sqr(r[i]+len)<h*h then continue;
t:=sqrt(sqr(r[s]+len)-h*h);
if t>=x0-x[s] then p:=true;
t:=t+sqrt(sqr(r[i]+len)-h*h);
if t>=x[i]-x[s] then p:=true;
end;
t:=sqrt(sqr(r[1]+len)-h*h);
if t<x[1] then exit(false);
exit(p);
end;
begin
readln(h,x0);
for i:=1 to 7 do readln(x[i],r[i]);
for i:=1 to 6 do
for j:=i+1 to 7 do
if x[i]>x[j] then
begin
x[0]:=x[i];x[i]:=x[j];x[j]:=x[0];
r[0]:=r[i];r[i]:=r[j];r[j]:=r[0];
end;
x[0]:=0;r[0]:=0;
ans:=maxlongint/2;
l1:=0;r1:=x0;
while l1<r1 do
begin
mid:=(l1+r1)/2;
if pd(mid) then
begin
r1:=mid-0.001;
ans:=min(ans,mid);
end
else l1:=mid+0.001;
end;
writeln(ans:0:2);
end.
For code:权当参考,不作承诺