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 "; #else const char LL[]="%lld "; #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; }