{题解}[jzoj3391]【NOIP2013模拟】穿越七色虹

jzoj3391

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:权当参考,不作承诺

你可能感兴趣的:({题解}[jzoj3391]【NOIP2013模拟】穿越七色虹)