Problem
在二维平面中,有很多半径均为 R R R的圆,其中 y y y轴负方向为重力方向。
它们在 0 0 0时刻圆心坐标为 ( x i , y i ) (x_i,y_i) (xi,yi),且速度矢量为 v ⃗ i = ( v x i , v y i ) \vec v_i=(v_{xi},v_{yi}) vi=(vxi,vyi),做斜抛运动。
问在给定时间区间 [ 0 , E ] [0,E] [0,E]内,一条直线最多能同时穿过多少个圆?
n ≤ 100 ; R , E ≤ 1000 n\leq 100;R,E\leq 1000 n≤100;R,E≤1000
Solution
可以证明必然有一种最优情况下,这条直线和某两个圆相切,因为如果不满足该条件,那么可以通过先平移该直线直到和某个圆相切,再绕切点旋转的方法得到一条新的直线,且不使得穿过的圆的数量减少。
可以证明必然有一种最优情况下,该直线必定是两个圆的外公切线(即圆心在该公切线的同侧)。
注意到每个圆的半径都相等,那么外公切线其实和两圆圆心的连线是平行的。那么我们其实可以把该直线平移到与圆心连线平行,再将其他所有的圆的半径相应地增加R,问题依然等价,避免了求公切线的麻烦。问题转化为了求动点到动直线的距离。
我们可以考虑枚举两个圆,如果能求出第三个圆被该直线穿过的时间区间,那么就可以方便地按照时间DP即可求出最大覆盖,并更新答案。
考虑枚举了三个圆之后,如何求相应的时间区间。我们以第一个圆为参考系,这样就只需要考虑相对速度,圆变成了直线运动
x 1 ′ = v x 1 ′ t + x 1 , y 1 ′ = v y 1 ′ t + y 1 (1) x_1'=v_{x1}'t+x_1,y_1'=v_{y1}'t+y_1 \tag 1 x1′=vx1′t+x1,y1′=vy1′t+y1(1)
x 2 ′ = v x 2 ′ t + x 2 , y 2 ′ = v y 2 ′ t + y 2 (2) x_2'=v_{x2}'t+x_2,y_2'=v_{y2}'t+y_2 \tag 2 x2′=vx2′t+x2,y2′=vy2′t+y2(2)
动直线的方程:
y
=
k
x
=
y
1
′
x
1
′
x
(3)
y=kx=\frac {y_1'} {x_1'}x \tag 3
y=kx=x1′y1′x(3)
则要解的方程为:
∣
y
2
′
−
k
x
2
′
∣
k
2
+
1
≤
4
R
2
(4)
\frac {|y_2'-kx_2'|} {\sqrt{k^2+1}}\leq 4R^2 \tag 4
k2+1∣y2′−kx2′∣≤4R2(4)
联立
(
1
)
(
2
)
(
3
)
(
4
)
(1)(2)(3)(4)
(1)(2)(3)(4)式,整理得:
(
y
2
′
x
1
′
−
y
1
′
x
2
′
)
2
−
4
R
2
(
(
x
1
′
)
2
+
(
y
1
′
)
2
)
≤
0
(5)
(y_2'x_1'-y_1'x_2')^2-4R^2\biggl((x_1')^2+(y_1')^2\biggr)\leq 0 \tag 5
(y2′x1′−y1′x2′)2−4R2((x1′)2+(y1′)2)≤0(5)
是一个关于 t t t的四次方程,使用牛顿迭代解之,判断区间用穿针引线法即可。
需要注意的是牛顿迭代不一定能解分式的根,故把分式全都去掉,整理出了 ( 5 ) (5) (5)式。另外需要注意在两边同乘分母的时候,乘的都是正数,故无需再讨论不等号方向。
理论时间复杂度 O ( n 3 ) O(n^3) O(n3),但解方程的复杂度略高导致常数很大。
Code
老年嘴巴选手不写代码
千万不要试图做防AK题,要折寿了