bzoj4570 [Scoi2016]妖怪

来源:互联网 发布:榨菜的危害 知乎 编辑:程序博客网 时间:2024/05/02 07:45

【题意】平面中给出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 2147483647using namespace std;struct aa{int w1, w2;}a[N];int n, w1[N], w2[N], l1, d[N];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;}


0 0
原创粉丝点击