tyvj 2053 [Nescafé29]穿越七色虹

78 篇文章 0 订阅

http://www.elijahqi.win/archives/1398
背景
在Nescafe27和28中,讲述了一支探险队前往Nescafe之塔探险的故事……
当两位探险队员以最快的时间把礼物放到每个木箱里之后,精灵们变身为一缕缕金带似的光,簇簇光芒使探险队员们睁不开眼睛。待一切平静下来之后,探险队员来到了一座宫殿中,玉制的石椅上坐着两个人……
“你们就是……Nescafe之塔护法中的两位?”
“是的,我们就是神刀护法xlk和飞箭护法riatre……你们来这里做什么?”
“我们是前来拜访圣主和四位护法的……”
“如果你们想见圣主和其它两位护法,你们必须穿过前方的七色彩虹。请随我来吧……”
描述
探险队员们跟随两位护法来到了七色虹前。七色虹,就是平面直角坐标系中赤橙黄绿青蓝紫七个半圆,第i座(1<=i<=7)半圆形彩虹的圆心是(xi,0),半径是ri,半圆上所有点的纵坐标均为非负数。探险队员可以看做一条竖直的、长度等于身高的线段,线段的底端纵坐标为0,最高的一位探险队员的身高为h。

现在探险队员们要从(0,0)穿越七色虹到达(x0,0),穿越七色虹的过程中,探险队员的整个身体必须始终在至少一个半圆形彩虹的内部。由于彩虹的半径ri可能太小了,不足以满足这个条件,因此两位护法决定帮助他们把所有彩虹的半径都增大一个非负实数r。探险队员们想知道,r最小是多少呢?
输入格式
第一行两个实数h、x0,表示身高和目的地横坐标。
接下来七行每行两个实数xi、ri,表示七座半圆形彩虹的圆心和半径。
输出格式
输出最小的r,四舍五入保留2位小数。
测试样例1
输入
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
输出
1.00
备注
对于 100% 的数据,满足0<=xi,x0<=10000,0< h< 100。

因为随着答案的增加可以通过的圆圈越多 所以二分很有效

我首先先针对数据进行了去重

然后每次枚举增加的那个值我可以通过半径 还有高度求出 他经过这个半圆的长度 然后 我去看这个长度能否连续覆盖到我的x0就好了 注意sqrt可能为负数所以需要特判

#include<cstdio>
#include<cmath>
#include<algorithm>
#define rps 1e-4
using namespace std;
inline bool judge1(double l,double r){
    if (r-l>rps) return true;else return false; 
}
struct node{
    double r,x;
}data[10];
struct node1{
    double l,r;
}line[10];
inline bool cmp1(node1 a,node1 b){return a.l==b.l?a.r<b.r:a.l<b.l;}
double h,x0,x[10],r[10],r1[10];int n;
inline bool judge(double mid){
    for (int i=1;i<=n;++i) r1[i]=r[i]+mid;
    for (int i=1;i<=n;++i) {
        if (r1[i]*r1[i]-h*h<0) return 0;
        line[i].l=x[i]-sqrt(r1[i]*r1[i]-h*h),line[i].r=x[i]+sqrt(r1[i]*r1[i]-h*h);
    }
    sort(line+1,line+n+1,cmp1);
    //for (int i=1;i<=n;++i) printf("%f %f\n",line[i].l,line[i].r);
    if (line[1].l>0) return 0;
    double rmax=line[1].r,lmax=line[1].l;
    for (int i=2;i<=n;++i){
        if (line[i].l>rmax) return 0;
        if (line[i].r<=rmax) continue;
        lmax=line[i].l;rmax=line[i].r;if (rmax>=x0) return 1;
    } 
    if (rmax<x0) return 0;else return 1;
}
inline bool cmp(node a,node b){return a.x<b.x;}
int main(){
    //freopen("rainbow.in","r",stdin);
    scanf("%lf",&h);scanf("%lf",&x0);
    for (int i=1;i<=7;++i) scanf("%lf%lf",&x[i],&r[i]),data[i].x=x[i],data[i].r=r[i];
    //for (int i=1;i<=7;++i) printf("%f %f\n",x[i],r[i]);
    sort(data+1,data+8,cmp);
    for (int i=1;i<=7;++i) x[i]=data[i].x,r[i]=data[i].r;
    //for (int i=1;i<=7;++i) printf("%f %f\n",x[i],r[i]);
    double lmax=x[1]-r[1],rmax=x[1]+r[1];
    for (int i=2;i<=7;++i){
        if (x[i]-r[i]>=lmax&&x[i]+r[i]<=rmax) data[i].x=50000,data[i].r=0;
        else lmax=x[i]-r[i],rmax=x[i]+r[i];
    }sort(data+1,data+8,cmp);n=7;
    for (int i=1;i<=7;++i) if (data[i].r!=0) x[i]=data[i].x,r[i]=data[i].r;else n=i;
    //for (int i=1;i<=n;++i) printf("%f %f\n",x[i],r[i]);
    double l=0,r=10000;
    //judge(0);
    while (judge1(l,r)){
        double mid=(l+r)/2;
        if (judge(mid)) r=mid;else l=mid;
    }printf("%.2f",r);
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值