P3291 [SCOI2016]妖怪

P3291 [SCOI2016]妖怪

链接

P3291 [SCOI2016]妖怪

题解

本来是想写凸包的,但是人太懒了。。。。
把每个妖怪视为平面上点,那么就是要找到一个斜率,使这个斜率经过每个点得到的最大截距和最小。
显然答案是在凸包上的,对于每个斜率,都可以在凸包上找到最优的点。
每个凸包上的点都在某个区间的斜率的时候是最大值,找到每个点最大时的区间在讨论即可。。。效率是\(O(nlogn)\)
然而我没写凸包。。。
因为这个显然可以二分答案的。。二分答案后我们要求每个点符合条件时的斜率区间,然后合并一下就行。
效率是\(O(nlogV)\) 的。

\(Code\)

#include <bits/stdc++.h>
#define LL long long
using namespace std;
const int N=1e6+10;
const double eps=1e-6;
const double INF=1e16;
const double X4=4;
const double X2=2;
const double X0=0;
int read(){
    int x=0,f=1;char ch=getchar();
    while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
    while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
void print(LL x){
    if(x>9) print(x/10);
    putchar(x%10+'0');
}

int n; 

struct node{
    double x,y;
}a[N];

int main(){
    scanf("%d",&n);
    for(int i=1;i<=n;++i){
        a[i].x=read();
        a[i].y=read();
    }
    double l=0,r=1e9,mid,A,B,C,mn,mx,del;
    bool flag=0;
    while(r-l>eps){ 
        mid=(l+r)/2;
        flag=0;
        mn=-INF;mx=INF;
        for(int i=1;i<=n;++i){
            A=a[i].x;
            B=-(mid-a[i].x-a[i].y);
            C=a[i].y;
            del=B*B-X4*A*C;
            if(del<0) {
                flag=1;break;
            }
            mx=min(mx,(-B+sqrt(del))/X2/A);
            mn=max(mn,(-B-sqrt(del))/X2/A);
        }
        if(mn<=mx&&mx>X0&&flag==0) r=mid;
        else l=mid;
    }
    printf("%0.4lf\n",l);
    return 0;
}
posted @ 2020-10-10 16:51  Iscream-2001  阅读(136)  评论(0编辑  收藏  举报
/* */ /* */