BZOJ4570:[SCOI2016]妖怪——题解
https://www.lydsy.com/JudgeOnline/problem.php?id=4570
邱老师是妖怪爱好者,他有n只妖怪,每只妖怪有攻击力atk和防御力dnf两种属性。邱老师立志成为妖怪大师,于是他从真新镇出发,踏上未知的旅途,见识不同的风景。
环境对妖怪的战斗力有很大影响,在某种环境中,妖怪可以降低自己k*a点攻击力,提升k*b点防御力或者,提升自己k*a点攻击力,降低k*b点防御力,a,b属于正实数,k为任意实数,但是atk和dnf必须始终非负。
妖怪在环境(a,b)中的战斗力为妖怪在该种环境中能达到的最大攻击力和最大防御力之和。strength(a,b)=max(atk(a,b))+max(dnf(a,b))环境由a,b两个参数定义,a,b的含义见前文描述。
比如当前环境a=3,b=2,那么攻击力为6,防御力为2的妖怪,能达到的最大攻击力为9,最大防御力为6。所以该妖怪在a=3,b=2的环境下战斗力为15。
因此,在不同的环境,战斗力最强的妖怪可能发生变化。
作为一名优秀的妖怪训练师,邱老师想发掘每一只妖怪的最大潜力,他想知道在最为不利的情况下,他的n只妖怪能够达到的最强战斗力值,即存在一组正实数(a,b)使得n只妖怪在该环境下最强战斗力最低。
对于每个妖怪当点,那么就相当于是找一个斜率,使得过点之后其中最外面的线的截距之和。
那么维护一个右上凸壳,我们不难发现当y=kx+b这条直线过(x0,y0)点的时候,我们所要求的答案即为y0+x0-(kx0+y0/k),是一个对勾函数,求出k的取值后分类讨论即可。
要注意特判一个点和两个点的情况。
#include<map> #include<cmath> #include<stack> #include<queue> #include<cstdio> #include<cctype> #include<vector> #include<cstdlib> #include<cstring> #include<iostream> #include<algorithm> using namespace std; typedef long long ll; typedef double dl; const int N=1e6+5; const int INF=1e9; const dl eps=1e-6; inline int read(){ int X=0,w=0;char ch=0; while(!isdigit(ch)){w|=ch=='-';ch=getchar();} while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar(); return w?-X:X; } struct point{ dl x,y; point(dl xx=0,dl yy=0){x=xx;y=yy;} point operator -(const point &b)const{ return point(x-b.x,y-b.y); } dl operator *(const point &b)const{ return x*b.y-y*b.x; } bool operator <(const point &b)const{ return x==b.x?y<b.y:x<b.x; } }p[N],q[N]; int n,l,per[N]; void graham(){ sort(p+1,p+n+1); for(int i=1;i<=n;i++){ while(l>=2&&(q[l]-q[l-1])*(p[i]-q[l])>=0)l--; q[++l]=p[i]; } } inline dl slope(point u,point v){ if(u.x==v.x)return INF; return (u.y-v.y)/(u.x-v.x); } inline dl suan(dl k1,dl k2,dl x0,dl y0){ dl maxn=-sqrt(y0/x0),tmp; if(maxn<k1)tmp=k1*x0+y0/k1; else if(maxn<=k2)tmp=maxn*x0+y0/maxn; else tmp=k2*x0+y0/k2; return y0+x0-tmp; } int main(){ n=read(); for(int i=1;i<=n;i++)p[i].x=read(),p[i].y=read(); graham(); dl ans=INF; if(l==1){ printf("%.4lf\n",suan(-INF,INF,q[1].x,q[1].y)); return 0; } if(l==2){ dl k=slope(q[1],q[2]); if(k>0){ printf("%.4lf\n",suan(-INF,INF,q[2].x,q[2].y)); return 0; } } int L,R; for(int i=1;i<=l;i++){ int j=i+1; dl k1=slope(q[i],q[j]); if(k1>0)continue; L=i;break; } for(int i=L;i<=l;i++){ int j=i+1; dl k1=slope(q[i],q[j]); if(k1>0){R=i;break;} } for(int i=L;i<=R;i++){ dl l1=slope(q[i],q[i+1]); dl l2=slope(q[i],q[i-1]); if(l1>0)l1=-INF; if(l2>0)l2=0; ans=min(ans,suan(l1,l2,q[i].x,q[i].y)); } printf("%.4lf\n",ans); return 0; }
+++++++++++++++++++++++++++++++++++++++++++
+本文作者:luyouqi233。 +
+欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+
+++++++++++++++++++++++++++++++++++++++++++