[CERC 2018] Reservoir Dog

吃了语文不好的亏啊...

题目链接:LOJluogu

首先令 \(T_f=0\),让 \(T_d\) 平移到原先 \(T_d-T_f\) 的时刻,这样可以方便我们后续的计算。接着考虑二分,因为我们懒得去想狗具体怎么蛇皮走位,所以为了省事可以二分答案来判断狗是否能够在指定位置接到盘子。假设狗接到盘子时的位置是 \((x,y)\),那么根据平抛运动的公式可以得出:

\[\begin{cases} V_f\cdot t=x\\ \frac{1}{2}a_ft^2=H_f-y\\ a_f=1\\ \end{cases} \]

也就是说如果我们二分了狗接盘子的横坐标 \(x\),就可以很快计算出对应的纵坐标 \(y\) 以及时间 \(t\),接着就只需要考虑如何判断狗是否能按时到达指定地点了。注意这里 \(\texttt{Clarifications}\) 说的是,狗的跳跃过程是瞬间获得能够跳到 \(H_d\) 高度的垂直速度,其实这还是有一点歧义的。真正的题意是:狗的跳跃过程是瞬间获得能够在未来某一时刻恰好到达 \(H_d\) 高度的速度(即到达 \(H_d\) 这个高度时正好垂直速度为 \(0\))。也就是说不存在先到达 \((x,0)\),再原地起跳直接到达 \(H_d\) 并在途中顺便接到处于 \((x,y)\) 的盘子这种情况的,也并不是说狗提前在某一时刻原地起飞到 \(H_d\) 之后再自由落体的,而是在竖直方向产生一个最高点为 \(H_d\) 的竖直上抛运动,本人就因为这个 \(\texttt{WA}\) 了好几发。

既然不能直接原地起跳接住盘子,那这也就意味着小狗需要先提前在某个位置跳起,再依靠重力让其水平方向到达 \(x\) 时恰好到达 \((x,y)\)。不过这里我们不能借助公式来计算小狗起跳时的位置,而是要考虑小狗在垂直方向的位移来计算跳跃所花费的时间,因为小狗在水平方向上移动的速度是不确定的。那么设小狗起跳后到达 \(y\) 这一高度所花的时间为 \(t_j\),起跳时瞬间获得的竖直方向的速度为 \(v_0\),就有方程:

\[\begin{cases} v_0t_j-\frac{1}{2}a_dt_j^2=y\\ a_d=3\\ \end{cases} \]

在解这个方程前我们还需要先算出 \(v_0\) 的值,那么借助物理学中关于竖直上抛运动的一个公式 \(H=\frac{v_0^2}{2g}\)(可用动能定理证明)就能得出 \(v_0=\sqrt{6H_d}\)。带回到原式中解一个一元二次方程就能得到 \(t_j=\frac{\sqrt{6H_d}\pm \sqrt{6H_d-6y}}{3}\),显然我们是要取更小的解。于是结合小狗要出发后才能起跳这一信息,我们得知了小狗能够到达 \((x,y)\) 的一个必要条件,那就是:

\[t-T_d\ge \frac{\sqrt{6H_d}- \sqrt{6H_d-6y}}{3} \]

除了这一条件外,我们还需要保证 \(y\le H_d\) 以及 \(V_d\cdot (t-T_d)\ge x\) ,这样就能完成对小狗能否到达 \((x,y)\) 的判断,这时对应的答案就是 \(t+\frac{x}{V_d}\)

当然不要忘了 \(\texttt{Clarifications}\) 中的另外一条:当飞盘落在地面上时瞬间停止运动。所以我们需要注意二分的区间,即飞盘落地时所处的位置 \(x_R\)。同样可以列出方程

\[\begin{cases} V_f\cdot t=x_R\\ \frac{1}{2}a_ft^2=H_f\\ a_f=1\\ \end{cases} \]

算出 \(x_R=V_f\sqrt {2H_f}\) 就能够确定二分的右端点。最后再处理一下狗无法在空中接到盘子的情况,这一情况的答案为 \(\max(\frac{x_R}{V_f},T_d+\frac{x_R}{V_d})+\frac{x_R}{V_d}\),取 \(\max\) 的部分是为了比较狗到达指定地点的时间和飞盘实际落地的时间,这样就大功告成了。

注意 \(\texttt{eps}\) 不要开太小,否则会因为精度问题而导致死循环。

#include<bits/stdc++.h>
using namespace std;
#define ld double
const ld eps=1e-6;
ld tf,vf,hf,td,vd,hd,l,r,x,ans;
int main()
{
	cin>>tf>>vf>>hf>>td>>vd>>hd;
	td-=tf;
	r=vf*sqrt(2*hf);
	ans=max(r/vf,td+r/vd)+r/vd;
	while(l+eps<r){
		x=(l+r)*0.5;
		ld t=x/vf;
		ld y=hf-0.5*t*t;
		if(hd>=y && (t-td)>=max(x/vd,(sqrt(6*hd)-sqrt(6*hd-6*y))/3))
			r=x,ans=min(ans,t+x/vd);
		else l=x;
	}
	printf("%.8f\n",ans+tf);
}

其实这题还有一种直接算答案的做法,大体思路就是把之前判断部分的式子重新写出来,然后算出每个不等式对应的约束,解完方程后再判断一下就好了,就是求解的过程略微有点麻烦,感兴趣的大佬们可以自行尝试。

posted @ 2022-07-20 18:41  DeaphetS  阅读(81)  评论(0编辑  收藏  举报