[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
*/