torus711 のアレ

主に競技プログラミングの問題について書きます.PC 以外だと数式が表示されないかもしれないです

AtCoder Beginner Contest 183, B : Billiards

問題概要

 二次元空間を考える.$X$ 軸は鏡面である.
 ここで,$( S_x, S_y )$ から光を発射して,鏡面に反射させ,$( G_x, G_y )$ に光を届けることを考える.鏡面にぶつかるときの $x$ 座標の値はいくらか?

制約

  • $-10^6 \leq S_x, G_x \leq 10^6$
  • $0 < S_y, G_y \leq 10^6$
  • $S_x \neq G_x$

解法

 $S_y$ を $-1$ 倍してあげると,$( S_x, -S_y )$ から $( G_x, G_y )$ への線分が $X$ 軸に交差するときの $x$ 座標を求める問題に言い換えることができます.このとき,$\mathit{ dy } = G_y - (-S_y), \mathit{ dx } = G_x - S_x$ とすると,$\theta = \frac { \mathit{ dx } } { \mathit{ dy } }$ で $y$ が $1$ 変化したときの $x$ の変化量を求められます.$X$ 軸に交差するまでの $y$ 座標の値の変化分というのは $S_y$ ですから,$S_x + S_y \times \theta$ で答えが求まります.

コード

main = do
	[ sx, sy, gx, gy ] :: [Double] <- map fromIntegral <$> readInts
	let
		sy' = -sy
		dx = gx - sx
		dy = gy - sy'
		theta = dx / dy
	printf "%.12f\n" $ sx + sy * theta