您的位置:首页 > 其它

bzoj4570 [Scoi2016]妖怪

2016-11-26 23:48 176 查看
【题意】平面中给出n个点,请你设定一个k值,使得过每个点作一条k<0的直线,每条直线横纵截距之和的最大值最小。

【数据范围】n<=10^6

【思路】二分答案,TLE

正解是求出一个上凸壳,对于凸壳上的每个点,计算出它是最大值时k的范围,更新答案。

【时间复杂度】O(n log n)#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#define N 1000010
#define inf 2147483647
using namespace std;

struct aa{int w1, w2;}a
;
int n, w1
, w2
, l1, d
;
double ans, last, now, p;

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

bool cmp(aa a, aa b){
if(a.w1!=b.w1)return a.w1<b.w1;
return a.w2<b.w2;
}

double slop(int i, int j){return 1.0*(a[i].w2-a[j].w2)/(a[i].w1-a[j].w1);}

int main(){
n=read();
for(int i=1; i<=n; i++){a[i].w1=read(); a[i].w2=read();}
sort(a+1, a+1+n, cmp); l1=0;
for(int i=1; i<=n; i++){
while(l1&&a[d[l1]].w2<=a[i].w2)l1--;
while(l1>=2&&slop(d[l1-1], d[l1])<=slop(d[l1], i))l1--;
d[++l1]=i;
}
for(int i=1; i<=l1; i++){w1[i]=a[d[i]].w1; w2[i]=a[d[i]].w2;}
ans=inf; last=0;
for(int i=1; i<=l1; i++){
if(i<=l1-1)now=-slop(d[i], d[i+1]); else now=inf;
p=sqrt(1.0*w2[i]/w1[i]);
if(last<=p&&p<=now)ans=min(ans, w1[i]+w2[i]+2*sqrt(w1[i])*sqrt(w2[i]));
else if(now<p)ans=min(ans, w1[i]+w2[i]+w1[i]*now+1.0*w2[i]/now);
else ans=min(ans, w1[i]+w2[i]+w1[i]*last+1.0*w2[i]/last);
last=now;
}
printf("%.4f", ans);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: