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;
}