版权声明:转载请声明出处,谢谢配合。 https://blog.csdn.net/zxyoi_dreamer/article/details/88838057
洛谷传送门
BZOJ传送门
LOJ传送门
解析:
首先观察到每个精灵的战斗力就是 。
由均值不等式:
我们并不关心 的实际值,我们只关心它们的比值,设
我们发现每一个精灵的战斗力关于 是单峰下凸的,所有精灵的战斗力取 仍然是单峰下凸的。于是就可以三分了。
为了精度,三分的次数显然太多了。那个
太大了。。。
然而我卡常技巧不够,卡过了洛谷和LOJ,卡不过BZOJ老爷机。。。
我们发现,能够成为最大值的只有上凸壳上的点,用水平序把上凸壳搞出来。
显然一个点成为最大值的范围就是在斜率范围中。
一个点能够取到最小值的时候 ,这时候
看一下这个 在不在它能够取的斜率中就行了。
为了方便处理,我在凸包前后加了两个点。
代码(三分):
#pragma GCC optimize(3)
#include<bits/stdc++.h>
#define ll long long
#define re register
#define gc get_char
#define cs const
namespace IO{
inline char get_char(){
static cs int Rlen=1<<20|1;
static char buf[Rlen],*p1,*p2;
return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
}
inline int getint(){
re char c;
while(!isdigit(c=gc()));re int num=c^48;
while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
return num;
}
}
using namespace IO;
using std::cout;
using std::cerr;
using std::max;
cs int N=1e6+6;
int n;
int x[N],y[N];
inline double F(double d){
double ans0=0,ans1=0,ans2=0,ans3=0,ans4=0,ans5=0,ans6=0,ans7=0;
int *p1=x+1,*p2=y+1;
re int rep=n>>3;
while(rep--){
ans0=max(ans0,p1[0]+p1[0]*d+p2[0]+p2[0]/d);
ans1=max(ans1,p1[1]+p1[1]*d+p2[1]+p2[1]/d);
ans2=max(ans2,p1[2]+p1[2]*d+p2[2]+p2[2]/d);
ans3=max(ans3,p1[3]+p1[3]*d+p2[3]+p2[3]/d);
ans4=max(ans4,p1[4]+p1[4]*d+p2[4]+p2[4]/d);
ans5=max(ans5,p1[5]+p1[5]*d+p2[5]+p2[5]/d);
ans6=max(ans6,p1[6]+p1[6]*d+p2[6]+p2[6]/d);
ans7=max(ans7,p1[7]+p1[7]*d+p2[7]+p2[7]/d);
p1+=8;p2+=8;
}
switch(n&7){
case 7:ans6=max(ans6,p1[6]+p1[6]*d+p2[6]+p2[6]/d);
case 6:ans5=max(ans5,p1[5]+p1[5]*d+p2[5]+p2[5]/d);
case 5:ans4=max(ans4,p1[4]+p1[4]*d+p2[4]+p2[4]/d);
case 4:ans3=max(ans3,p1[3]+p1[3]*d+p2[3]+p2[3]/d);
case 3:ans2=max(ans2,p1[2]+p1[2]*d+p2[2]+p2[2]/d);
case 2:ans1=max(ans1,p1[1]+p1[1]*d+p2[1]+p2[1]/d);
case 1:ans0=max(ans0,p1[0]+p1[0]*d+p2[0]+p2[0]/d);
}
return max(max(max(ans0,ans1),max(ans2,ans3)),max(max(ans4,ans5),max(ans6,ans7)));
}
signed main(){
n=getint();
for(int re i=1;i<=n;++i)x[i]=getint(),y[i]=getint();
double l=1e-6,r=1e8;
while(l+1e-12<r){
double lmid=l+(r-l)/3;
double rmid=r-(r-l)/3;
if(F(lmid)>F(rmid))l=lmid;
else r=rmid;
}
printf("%.4f",F(l));
return 0;
}
代码(凸包):
#include<bits/stdc++.h>
#define ll long long
#define re register
#define gc get_char
#define cs const
namespace IO{
inline char get_char(){
static cs int Rlen=1<<20|1;
static char buf[Rlen],*p1,*p2;
return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
}
inline int getint(){
re char c;
while(!isdigit(c=gc()));re int num=c^48;
while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
return num;
}
}
using namespace IO;
using std::cout;
using std::cerr;
using std::max;
cs double eps=1e-9;
struct Point{
double x,y;
Point(){}
Point(cs double &_x,cs double &_y):x(_x),y(_y){}
friend Point operator-(cs Point &a,cs Point &b){return Point(a.x-b.x,a.y-b.y);}
friend double operator*(cs Point &a,cs Point &b){return a.x*b.y-b.x*a.y;}
};
bool cmp(cs Point &a,cs Point &b){
return a.x==b.x?a.y>b.y:a.x<b.x;
}
inline double slope(cs Point &a,cs Point &b){
double k=(a.y-b.y)/(a.x-b.x);
if(fabs(k)<eps)return -eps;
if(1/fabs(k)<eps)return -1/eps;
return k;
}
inline double calc(cs Point &a,double b){
return a.x+a.y+a.x*b+a.y/b;
}
cs int N=1e6+6;
int n;
Point p[N];
double ans=1e18;
inline void convex_hull(int m){
n=0;
for(int re i=1;i<=m;++i){
if(cmp(p[i],p[1]))std::swap(p[i],p[1]);
if(cmp(p[m],p[i]))std::swap(p[m],p[i]);
}
p[++m]=Point(0,p[1].y);
++m;p[m]=Point(p[m-2].x,0);
std::sort(p+1,p+m+1,cmp);
for(int re i=1;i<=m;++i){
while(n>1&&(p[i]-p[n])*(p[n]-p[n-1])<0)--n;
p[++n]=p[i];
}
}
signed main(){
n=getint();
for(int re i=1;i<=n;++i)p[i].x=getint(),p[i].y=getint();
convex_hull(n);
double ans=1e18,l=-1e9,r,k;
for(int re i=2;i<n;++i){
l=-slope(p[i],p[i-1]),r=-slope(p[i],p[i+1]),k=sqrt(p[i].y/p[i].x);
if(l<=k&&k<=r)ans=std::min(ans,calc(p[i],k));
ans=std::min(ans,std::min(calc(p[i],l),calc(p[i],r)));
}
printf("%.4f",ans);
return 0;
}