「SCOI2016」妖怪
玄妙...盲猜一个结论,然后过了,事后一证,然后假了,数据真水
首先要最小化
\[ \max_{i=1}^n (1+k)x_i+(1+\frac{1}{k})y_i \]
\(k\)是大于0的正实数
最大值显然在上凸包上,先把上凸包搞出来
然后每个点成为最大值时,\(k\)都有个取值范围(就是它左边或者右边的点成为最大值时)
然后对每个点用均值不等式得到最小值为
\[ \begin{aligned} z&=kx+\frac{1}{k}y+x+y\\ &\ge2\sqrt{xy}+x+y\\ \end{aligned} \]
在\(kx=\frac{y}{k}\)取到最小值,即\(k=\sqrt{\frac{y}{x}}\)
然后这个点成为最大值时,可能取到最小值的就两个端点和这个最小值点(如果这个最小值可以取的话)
最开始我没注意可以不等式,随便取了个\(k=\frac{y}{x}\),居然也过了,真神奇
Code:
#include <cstdio>
#include <cmath>
#include <algorithm>
using std::min;
const int N=1e6+10;
const double eps=1e-8;
struct Vector
{
double x,y;
Vector(){}
Vector(double X,double Y){x=X,y=Y;}
Vector friend operator -(Vector a,Vector b){return Vector(a.x-b.x,a.y-b.y);}
bool friend operator <(Vector a,Vector b){return fabs(a.x-b.x)<eps?a.y>b.y:a.x<b.x;}
}bee[N],s[N];
double Cross(Vector a,Vector b){return a.x*b.y-a.y*b.x;}
int n,tot;
double get(Vector a,Vector b)
{
double k=(b.y-a.y)/(b.x-a.x);
if(fabs(k)<eps) return -eps;
if(1/fabs(k)<eps) return -1/eps;
return k;
}
double cal(double k,Vector a)
{
if(k<eps) return 1e18;
return (1+k)*a.x+(1+1/k)*a.y;
}
int main()
{
scanf("%d",&n);
for(int i=1;i<=n;i++) scanf("%lf%lf",&bee[i].x,&bee[i].y);
std::sort(bee+1,bee+1+n);
bee[++n]=Vector(0,bee[1].y);
++n,bee[n]=Vector(bee[n-2].x,0);
std::sort(bee+1,bee+1+n);
for(int i=1;i<=n;i++)
{
while(tot>1&&Cross(bee[i]-s[tot],s[tot]-s[tot-1])<0) --tot;
s[++tot]=bee[i];
}
double ans=1e18;
for(int i=2;i<tot;i++)
{
double kl=-get(s[i],s[i-1]),kr=-get(s[i+1],s[i]),k=sqrt(s[i].x/s[i].y);
ans=min(ans,min(cal(kl,s[i]),cal(kr,s[i])));
if(kl<=k&&k<=kr)
ans=min(ans,cal(k,s[i]));
}
printf("%.4f\n",ans);
return 0;
}
2019.3.5