每个妖怪在指定环境下攻击和防御的变化量比值是一个定值,所以我们可以把妖怪看成平面上的点,横纵坐标为攻击和防御,对于每个妖怪环境看成一条k=-b/a的过该妖怪直线,每个妖怪的战斗力就是x=0时y的值加上y=0时x的值
所以我们要维护一个右上凸壳,用一条直线卡这个凸壳,假设卡到的妖怪是(x,y),我们可以用x+y-kx-y/k更新答案
对于每个单独妖怪,战斗力=x+y-kx-y/k,对勾函数,当k=-sqrt(y/x)时取得最小值
维护一个右上凸壳,对于每个凸壳上的妖怪,用他和他上一个妖怪连成的直线更新答案,然后算出这个妖怪的最优斜率,如果这个斜率的直线卡在凸包上的妖怪是这个妖怪则更新答案
复杂度O(n logn)
如果二分写的很优的话也可以过
设t=b/a
二分答案c,如果存在一个t使得对于所有妖怪x+y+tx+y/t<=c有解则c可行
等式两边同时乘以x,变为二次函数,相当于数轴上线段判有没有交,每次可以O(n)判断
复杂度O(n logINF/eps)反正我是特勒了
#include<iostream> #include<cstdlib> #include<cstdio> #include<cstring> #include<cmath> #include<ctime> #include<algorithm> #include<iomanip> #include<vector> #include<stack> #include<queue> #include<map> #include<set> #include<bitset> using namespace std; #define MAXN 1000010 #define MAXM 1010 #define ll long long #define INF 1000000000 #define MOD 1000000007 #define eps 1e-8 char xB[1<<15],*xS=xB,*xT=xB; #define getc() (xS==xT&&(xT=(xS=xB)+fread(xB,1,1<<15,stdin),xS==xT)?0:*xS++) inline int read(){ char ch=getc(); int f=1,x=0; while(!(ch>='0'&&ch<='9')){if(ch=='-')f=-1;ch=getc();} while(ch>='0'&&ch<='9'){x=x*10+(ch-'0');ch=getc();} return x*f; } struct pt{ int x; int y; pt(){ } pt(int _x,int _y){ x=_x; y=_y; } friend pt operator -(pt x,pt y){ return pt(x.x-y.x,x.y-y.y); } friend double operator *(pt x,pt y){ return 1.0*x.x*y.y-1.0*x.y*y.x; } friend bool operator <(pt x,pt y){ return x.x!=y.x?x.x<y.x:x.y>y.y; } }; int n; pt a[MAXN]; pt s[MAXN]; int tp; double ans=1e10; double k(pt &x){ return -sqrt(1.0*x.y/x.x); } double xl(pt &x,pt &y){ return x.x==y.x?-1e60:1.0*(x.y-y.y)/(x.x-y.x); } double cal(pt x,double k){ if(fabs(k)<eps){ return 1e20; } return 1.0*x.x+x.y-1.0*x.x*k-1.0*x.y/k; } int main(){ int i; n=read(); for(i=1;i<=n;i++){ a[i].x=read(); a[i].y=read(); } sort(a+1,a+n+1); for(i=1;i<=n;i++){ while(tp>=2&&(s[tp]-s[tp-1])*(a[i]-s[tp])>0){ tp--; } s[++tp]=a[i]; } double K; if(tp!=1){ K=k(s[1]); if(K>=xl(s[1],s[2])){ ans=min(ans,cal(s[1],K)); } K=k(s[tp]); if(K<=xl(s[tp-1],s[tp])){ ans=min(ans,cal(s[tp],K)); } ans=min(ans,cal(s[tp],xl(s[tp-1],s[tp]))); }else{ ans=cal(s[1],k(s[1])); } for(i=2;i<tp;i++){ K=k(s[i]); if(K<=xl(s[i-1],s[i])&&K>=xl(s[i],s[i+1])){ ans=min(ans,cal(s[i],K)); } ans=min(ans,cal(s[i],xl(s[i-1],s[i]))); } printf("%.4lf\n",ans); return 0; } /* */
时间: 2024-10-16 07:22:07