题解 P3291 【[SCOI2016]妖怪】
【题解】妖怪 [SCOI2016] [P3291] [Bzoj4570]
传送门:[妖怪
【题目描述】
给出
【分析】
感觉网上很多题解都没讲清楚。
【Solution #1】
设
求最大的最小很明显要二分,每次检查是否存在一个正实数
易知
时间复杂度:
代码就不放了(懒)。
【Solution #2】
此为正解。
设
假设有一条斜率为
把这玩意儿加起来试试?
发现其表示式和
也就是说
假设当前
反过来想,对于凸包上的每一个点
已知当
如果
除了求上凸包要排序,决策都是线性的,时间复杂度:
(毒瘤
【Code】
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<cmath>
#define LD double
#define LL long long
#define Vector Point
#define Re register int
using namespace std;
const int N=1e6+3;
const LD eps=1e-8;
inline int dcmp(LD a){return a<-eps?-1:(a>eps?1:0);}
int n,t;LD ans=1e18;
inline void in(Re &x){
int f=0;x=0;char c=getchar();
while(c<'0'||c>'9')f|=c=='-',c=getchar();
while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();
x=f?-x:x;
}
struct Point{int x,y;Point(Re X=0,Re Y=0){x=X,y=Y;}}P[N],cp[N];
inline LL Cro(Vector a,Vector b){return (LL)a.x*b.y-(LL)a.y*b.x;}
inline Vector operator-(Vector a,Vector b){return Vector(a.x-b.x,a.y-b.y);}
inline bool cmp(const Point &A,const Point &B){return A.x!=B.x?A.x<B.x:A.y>B.y;}
inline LD getk(Point a,Point b){return (LD)(a.y-b.y)/(a.x-b.x);}
inline LD calc(Point a,LD k){return dcmp(k)?a.x+a.y-a.x*k-a.y/k:1e18;}
int main(){
// freopen("123.txt","r",stdin);
in(n);
for(Re i=1;i<=n;++i)in(P[i].x),in(P[i].y);
sort(P+1,P+n+1,cmp);
for(Re i=1;i<=n;++i){
while(t>1&&Cro(cp[t]-cp[t-1],P[i]-cp[t-1])>=0)--t;
cp[++t]=P[i];
}
for(Re i=1;i<=t;++i){
LD k=-sqrt((LD)cp[i].y/cp[i].x);
if((i==1||dcmp(k-getk(cp[i],cp[i-1]))<=0)&&(i==t||dcmp(k-getk(cp[i],cp[i+1])>=0)))ans=min(ans,calc(cp[i],k));
if(i>1)ans=min(ans,calc(cp[i],getk(cp[i],cp[i-1])));
if(i<t)ans=min(ans,calc(cp[i],getk(cp[i],cp[i+1])));
}
printf("%.4lf\n",ans);
}