Link:

Codeforces #514 传送门

很简单的一场比赛打崩了也是菜得令人无话可说……

D:

一眼二分,发现对于固定的半径和点,能包含该点的圆的圆心一定在一个区间内,求出区间判断即可

此题一个重要性质就是圆与$x$轴相切,画出圆心所在直线后就能想到上述贪心了

#include <bits/stdc++.h>

using namespace std;
#define X first
#define Y second
#define pb push_back
typedef double db;
typedef long long ll;
typedef pair<db,db> P;
const db eps=1e-7;
const int MAXN=1e5+10;
struct Data{db l,r;int id;}a[MAXN];
int n,cnt1,cnt2;P dat[MAXN];

bool cmp(Data a,Data b)
{return a.l<b.l;}
db sqr(db x){return 1.0*x*x;}
bool cal(db r,int k)
{
    db b=2*dat[k].X;
    db c=sqr(dat[k].X)+sqr(dat[k].Y-r)-sqr(r);
    if(sqr(b)-4*c<-eps) return false;
    a[k].id=k;
    a[k].l=(b-sqrt(sqr(b)-4*c))/2.0;
    a[k].r=(b+sqrt(sqr(b)-4*c))/2.0;
    return true;
}
bool check(db r)
{
    if(cnt1) r=-r;
    for(int i=1;i<=n;i++)
        if(!cal(r,i)) return false;
    db mn=1e60,mx=-1e60;
    for(int i=1;i<=n;i++)
        mn=min(mn,a[i].r),mx=max(mx,a[i].l);
    return mx<=mn;
}

int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%lf%lf",&dat[i].X,&dat[i].Y);
        cnt1+=dat[i].Y<0;cnt2+=dat[i].Y>0;
    }
    if(n==1) return printf("%.6lf",dat[1].Y/2.0),0;
    if(cnt1&&cnt2) return puts("-1"),0;
    
    //实数二分最好直接枚举次数,否则精度可能不够 
    // 也可以相对误差和eps比较 
    db l=0,r=1e16;
    for(int i=1;i<=200;i++)
    {
        db mid=(l+r)/2.0;
        if(check(mid)) r=mid;
        else l=mid;
    }
    printf("%.6lf",l);
    return 0;
}
Problem D

相关文章: