2019.03.27【SCOI2016】【洛谷P3291】【BZOJ4570】【LOJ2015】妖怪(凸包)(三分?)

版权声明:转载请声明出处,谢谢配合。 https://blog.csdn.net/zxyoi_dreamer/article/details/88838057

洛谷传送门

BZOJ传送门

LOJ传送门


解析:

首先观察到每个精灵的战斗力就是 a t k + d f n + b a a t k + a b d f n atk+dfn+\frac{b}aatk+\frac{a}bdfn

由均值不等式: b a a t k + a b d f n 2 a t k d f n \frac{b}aatk+\frac{a}bdfn\geq 2\sqrt{atk\cdot dfn}

我们并不关心 a , b a,b 的实际值,我们只关心它们的比值,设 k = b a k=\frac{b}{a}

我们发现每一个精灵的战斗力关于 k k 是单峰下凸的,所有精灵的战斗力取 max \max 仍然是单峰下凸的。于是就可以三分了。

为了精度,三分的次数显然太多了。那个 log \log 太大了。。。
然而我卡常技巧不够,卡过了洛谷和LOJ,卡不过BZOJ老爷机。。。

我们发现,能够成为最大值的只有上凸壳上的点,用水平序把上凸壳搞出来。

显然一个点成为最大值的范围就是在斜率范围中。

一个点能够取到最小值的时候 k a t k + d f n k = 2 a t k d f n k\cdot atk+\frac{dfn}k=2\sqrt{atk\cdot dfn} ,这时候 k a t k = d f n k       k = d f n a t k k\cdot atk = \frac{dfn}k\iff k=\sqrt{\frac{dfn}{atk}}

看一下这个 k k 在不在它能够取的斜率中就行了。

为了方便处理,我在凸包前后加了两个点。


代码(三分):

#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;
}

猜你喜欢

转载自blog.csdn.net/zxyoi_dreamer/article/details/88838057