[CF1059]Nature Reserve

题目

传送门

题解

一道十分巧妙的二分题 然而精度要求较高

首先考虑无解情况——有某两个点在 \(x\) 轴的上下方,此时输出 -1

否则,考虑二分这个圆的半径 \(r\),那么这个圆心所在的位置一定是一条直线 \(y=r\)(此处我们将所有的点都转移到 \(x\) 轴上方,故不考虑正负号问题),然后,根据 \(r\) 和所有点的位置,我们得以用勾股定理求得,要包含点 \((x_i,y_i)\) 的合法圆心的 \(x\) 坐标一定在 \([x_i-\sqrt{r^2-(y_i-r)^2},x_i+\sqrt{r^2-(y_i-r)^2}]\),然后我们将所有的区间取并集,如果最后的集合为空,说明 \(r\) 过小,不为空则继续往小二分。

代码

#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstdlib>
using namespace std;

const double eps=1e-8;
const int MAXN=1e5;

struct node{double x,y;}p[MAXN+5];

int n,pos;

double L,R;

template<class T>const T fab(const T a){return a<0?-a:a;}

inline void Init(){
    scanf("%d",&n);
    for(int i=1;i<=n;++i){
    	scanf("%lf %lf",&p[i].x,&p[i].y);
        if((p[i].y<0 && pos==1) || (p[i].y>0 && pos==-1)){
            puts("-1");
            exit(0);
        }else pos=(p[i].y<0)?-1:1,p[i].y=fab(p[i].y);
    }
}

inline bool Check(const double x){
	double l=-1e18,r=1e18,len;
	for(int i=1;i<=n;++i){
		if(p[i].y>2*x)return false;
		len=sqrt(p[i].y)*sqrt(2*x-p[i].y);
		l=max(l,p[i].x-len);
		r=min(r,p[i].x+len);
	}return l<r;
}

inline void Bisearch(){
	double mid,ans;
	R=1e18;
	for(int times=1;times<=1000;++times){
//		printf("Now L == %f, R == %f\n",L,R);
		mid=(L+R)/2;
		if(Check(mid))ans=R=mid;
		else L=mid;
	}
	printf("%f\n",ans);
}

signed main(){
    Init();
    Bisearch();
    return 0;
}
/*
2
-10000000 1
10000000 1
*/
posted @ 2020-07-20 07:50  Arextre  阅读(135)  评论(0编辑  收藏  举报