题目链接:Codeforces - D. Nature Reserve
首先肯定二分半径。
然后我们可以发现,半径确定之后,圆心肯定在一条直线上面。
然后我们可以发现对于每个点,都能找到满足覆盖这个点的区间,问题就转化为判断区间是否有交集。
AC代码:
#pragma GCC optimize("-Ofast","-funroll-all-loops")
#include<bits/stdc++.h>
//#define int long long
using namespace std;
const int N=1e5+10;
const double eps=1e-8;
long double x[N],y[N],l,r=1e18,mi=1e9,mx; int n,cnt; set<int> s;
inline int check(double mid){
long double cl=-1e18,cr=1e18;
for(int i=1;i<=n;i++){
if(y[i]>2*mid) return 0;
long double p=sqrt(2.0*y[i]*mid-y[i]*y[i]);
long double ql=x[i]-p,qr=x[i]+p;
cl=max(cl,ql),cr=min(qr,cr);
if(cl>cr) return 0;
}
return 1;
}
signed main(){
cin>>n;
for(int i=1;i<=n;i++){
cin>>x[i]>>y[i],mi=min(mi,y[i]),mx=max(mx,y[i]);
if(fabs(y[i])<eps) cnt++; s.insert((int)(x[i]));
y[i]=fabs(y[i]);
}
if((mx>0&&mi<0)||cnt>1) return puts("-1"),0;
if(s.size()==1){
long double mx=-1e18;
for(int i=1;i<=n;i++) mx=max(mx,y[i]);
return printf("%.10Lf\n",mx/2),0;
}
for(int i=1;i<=150;i++){
long double mid=(l+r)/2;
if(check(mid)) r=mid;
else l=mid;
}
printf("%.10Lf\n",l);
return 0;
}