2018.10.15 bzoj4570: [Scoi2016]妖怪(凸包)
阿新 • • 發佈:2018-12-15
傳送門 不得不說這題有點東西啊。
看到題第一眼二分,用二次函式求範圍來進行,20分滾粗了233. 於是開始思考正解。 發現可以把每隻怪物的二元組屬性看成二維座標。 這時對於一隻怪物,一種環境相當於是一條過了點的直線,貢獻就是在橫縱座標的截距之和。 觀察之後很容易發現答案只跟所有點的右上凸殼有關係。 於是我們維護所有點的上凸殼。 然後依次找每個點對答案的貢獻就行了。 程式碼:
#include<bits/stdc++.h>
#define db double
#define N 1000005
using namespace std;
inline int read(){
int ans=0;
char ch=getchar();
while(!isdigit(ch))ch=getchar();
while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
return ans;
}
int n,q[N],top=0;
struct pot{db x,y;}p[N];
const double inf=2e9,eps=1e-10;
inline bool cmp(const pot&a,const pot&b) {return a.x==b.x?a.y<b.y:a.x<b.x;}
inline double calc(const pot&a,double k){return a.x+a.y+a.x*k+a.y/k;}
inline double slope(const pot&a,const pot&b){return (a.y-b.y)/(a.x-b.x);}
inline pot operator-(const pot&a,const pot&b){return (pot){a.x-b.x,a.y-b.y};}
inline double operator ^(const pot&a,const pot&b){return a.x*b.y-a.y*b.x;}
inline double solve(){
double ret=inf,l=-inf,r,k;
for(int i=1;i<=top;++i){
r=l,l=i==top?-eps:slope(p[q[i]],p[q[i+1]]),k=-sqrt(p[q[i]].y/p[q[i]].x);
if(l<=k&&k<=r)ret=min(ret,calc(p[q[i]],-k));
else ret=min(ret,calc(p[q[i]],-l)),ret=min(ret,calc(p[q[i]],-r));
}
return ret;
}
int main(){
n=read();
for(int i=1;i<=n;++i)p[i].x=read(),p[i].y=read();
sort(p+1,p+n+1,cmp);
for(int i=n;i;--i){
while(top>2&&((p[i]-p[q[top-1]])^(p[q[top]]-p[q[top-1]]))>=0)--top;
q[++top]=i;
}
while(top>1&&p[q[top]].y<=p[q[top-1]].y)--top;
printf("%.4lf",solve());
return 0;
}