BZOJ4570 SCOI2016妖怪(三分)

  strength=atk*(1+b/a)+dnf*(1+a/b)。设a/b=x,可以发现这是一个关于x的对勾函数。开口向上的一堆凸函数取max还是凸函数,三分即可。

  然而无良出题人既卡精度又卡时间。众所周知三分的本质是二分(雾),所以开始三分时令每次取的两个点为中点±eps,最后再用真的三分微调即可。具体边界多试几次就行了。跑的挺快还能剩下1s(大雾)。

#include<iostream> 
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<algorithm>
using namespace std;
#define ll long long
#define N 1000010
int read()
{
    int x=0,f=1;char c=getchar();
    while (c<'0'||c>'9') {if (c=='-') f=-1;c=getchar();}
    while (c>='0'&&c<='9') x=(x<<1)+(x<<3)+(c^48),c=getchar();
    return x*f;
}
char getc(){char c=getchar();while ((c<'A'||c>'Z')&&(c<'a'||c>'z')) c=getchar();return c;}
int gcd(int n,int m){return m==0?n:gcd(m,n%m);}
int n;
struct data{int x,y;
}a[N];
double calc(double x)
{
    double s=0;
    for (int i=1;i<=n;i++) s=max(s,a[i].x*(1+x)+a[i].y*(1+1/x));
    return s;
}
int main()
{
#ifndef ONLINE_JUDGE
    freopen("bzoj4570.in","r",stdin);
    freopen("bzoj4570.out","w",stdout);
    const char LL[]="%I64d\n";
#else
    const char LL[]="%lld\n";
#endif
    n=read();
    for (int i=1;i<=n;i++) a[i].x=read(),a[i].y=read();
    double eps=1E-8;
    double l=eps,r=1/eps;
    while (l+1E-6<=r)
    {
        double mid1=(l+r)/2-eps,mid2=(l+r)/2+eps;
        if (calc(mid1)<calc(mid2)) r=mid2;
        else l=mid1;
    }
    for (int i=1;i<=35;i++)
    {
        double mid1=l+(r-l)/3,mid2=r-(r-l)/3;
        if (calc(mid1)<calc(mid2)) r=mid2;
        else l=mid1;
    }
    printf("%.4f",calc(l));
    return 0;
}

 

posted @ 2018-11-01 18:12  Gloid  阅读(108)  评论(0编辑  收藏  举报