Bzoj4570--Scoi2016妖怪

把每一个妖怪看出平面上的一个点(x,y),场地参数k=-a/b;

那么每个妖怪的战斗力即为过点(x,y)斜率为k的直线与坐标轴的交点的和

稍微画下图可以看出如果是最大战力的妖怪一定是在所有点所形成的右上凸包上

维护一个凸包,枚举凸包每一个点是最强妖怪时的最弱战力

要使一个点所形成的是最强战力,那么有过这个点i的斜率k i-1<k i<k i+1,算出每个点的最佳斜率k',如果k'满足条件则代入k'更新答案,再用i与i+1的斜率更新一下答案

代码如下 :

#include<bits/stdc++.h>
#define MAXN 1000005
#define MAXM 150005
#define fix 40000
#define INF 1000000000
#define eps 1e-9
#define LL long long
using namespace std;

struct P{
    double x,y;
    bool operator < (P b) const {return x>b.x;}
    double comp() {return x+y+2*sqrt(x*y);}
}p[MAXN],tb[MAXN];
double k[MAXN],ans=INF;
int n,top,ed;

inline double cross(P a,P b,P c) {
    a.x-=b.x;a.y-=b.y;b.x-=c.x;b.y-=c.y;
    return b.x*a.y-b.y*a.x;
}
inline double Get_K(P a,P b) {return (a.y-b.y)/(a.x-b.x);}

int main() {
    scanf("%d",&n);
    for(int i=1;i<=n;i++) {
        scanf("%lf%lf",&p[i].x,&p[i].y);
    }
    sort(p+1,p+1+n);
    for(int i=1;i<=n;i++) {
        while(top>1&&cross(p[i],tb[top],tb[top-1])<0) top--;
        tb[++top]=p[i];
    }
    k[0]=-INF;
    for(int i=1;i<=top;i++) {
        k[i]=Get_K(tb[i+1],tb[i]);
        ed=i;if(k[i]>=0) break;
    }
    k[ed]=-eps;
    for(int i=1;i<=ed;i++) {
        double mk=-sqrt(tb[i].y/tb[i].x),cg=INF,he;
        if(mk>k[i-1]&&mk<k[i]) cg=tb[i].comp();
        he=tb[i].x+tb[i].y-k[i]*tb[i].x-tb[i].y/k[i];
        cg=cg>he?he:cg;ans=ans>cg?cg:ans;
    }
    printf("%.4lf",ans);
    return 0;
} 

为了方便是把右上凸包的首尾斜率设置了一下

原文地址:https://www.cnblogs.com/ihopenot/p/5910902.html