D: Space Golf[二分+数学]

发布时间 2023-08-16 17:32:57作者: qbning

题意大概是给你一个小球,完全弹性碰撞,有若干高度的板子,问从0-target的最小合速度是多少。

完全弹性碰撞,意味着给定一个初始速度,运动轨迹将是一个抛物线的不相交的等距(d/(i+1))右移。i是弹跳次数

而确定好水平速度后,球的落点就是确定的,那么当y能过的时候,任何大于y的高度也能过去。所以我们可以用二分来求得跳一个固定次数时的最低高度是多少。

对于一个高度和跳的次数,我们可以求得最后的合速度的平方的一个式子

 

$v^2=2y+\frac{\frac{x^2}{4}}{2y}$

然后需要注意的是,这个式子说明$v^2$是和两个变量相关的。如果x为定值的时候,y作为自变量,$v^2$作为因变量,这是一个对勾函数

它的最小值所在处是$\frac{x}{2}$处。

这里就出现一个问题,如果我们求得的y是小于$\frac{x}{2}$的,那么$v^2$的最小值反而不是y最小处,而是$\frac{x}{2}$处。不能想当然认为y越小最后值就最小。

查看代码

#include<iostream>
#include<algorithm>
#include<cmath>
#include<vector>
#define eps 1e-8
#define g 1.0
using namespace std;
typedef long long ll;
double d,n,b;
struct ban
{
	double x,h;
	bool operator<(ban b)const
	{
		return x<b.x;
	}
}a[15];
double zx;
double hev(double zx,double zy)
{
	double vb=sqrt(2*zy),va=zx/2/sqrt(zy*2);
	if(zx/4>zy)
	return sqrt(zx);
	return sqrt(va*va+vb*vb);
}
double cal(double x,double m,double h)
{
	return -h*(x-m)*(x+m)/(m*m);
}
bool check(double zy)
{
	double h,t;
	double mid=zx/2;
	vector<int>inner;
	int x=1,y=1;
	while(x<=n)
	{
		inner.clear();
		while(a[x].x<=y*zx&&x<=n)
		{
			inner.push_back(x);
			x++;
		}
		for(auto sz:inner)
		{
			double xzb=a[sz].x-mid;
			if(a[sz].h>cal(xzb,zx/2,zy)+eps)
				return 0;
		}
		y++;
		mid+=zx;
	}
	return 1;
}
signed main()
{
	cin>>d>>n>>b;
	for(int i=1;i<=n;i++)
		cin>>a[i].x>>a[i].h;
	sort(a+1,a+1+(ll)n);
	double ans=1e10;
	for(int i=0;i<=b;i++)
	{
		zx=d/(i+1);
		double l=0,r=1e6;
		while(l+eps<r)
		{
			double mid=(l+r)/2;
			if(check(mid))
			{
				cout<<"1\n";
				r=mid;
			}
			else l=mid;
		}
		ans=min(ans,hev(zx,l));
	}
	printf("%.5lf",ans);
	return 0;
}