Official

C - Knight Fork Editorial by Nyaan


問題文をナイーブな全探索で実装する、すなわち \((x, y)\) を広い範囲から列挙して \((x_1, y_1)\) からの距離も \((x_2, y_2)\) からの距離も \(\sqrt{5}\) になる点があるか調べると次のようなコードになると思います。

# 距離の 2 乗を計算する関数
def dist_sq(a, b, c, d):
  return (a - c) ** 2 + (b - d) ** 2

# 答えを求める関数
def solve(x1, y1, x2, y2):
  for x in range(-2 * 10 ** 9, 2 * 10 ** 9 + 1):
    for y in range(-2 * 10 ** 9, 2 * 10 ** 9 + 1):
      if dist_sq(x, y, x1, y1) == dist_sq(x, y, x2, y2) == 5:
        return "Yes"
  return "No"

しかしこれは計算量が (\(x\) の範囲) \(\times\) (\(y\) の範囲) となってしまうため TLE してしまいます。

これはこの問題に限らず重要な話ですが、困った時はサンプルを図に書いて考察する のが問題を解く上で大事です。さっそく図を書いてみましょう。

サンプル \(1\) において、\((x_1, y_1)\) および \((x_1, y_1)\) から距離 \(\sqrt{5}\) の格子点を丸、\((x_2, y_2)\) および \((x_2,y_2)\) から距離 \(\sqrt{5}\) の格子点を三角で示したのが以下の図になります。

image

図を描いて考えると、どうやら調べる必要があるのは 「\((x_1, y_1)\) を中心とした \(4 \times 4\) 四方に含まれる点」だけでよいことが分かると思います。なぜならば、その範囲の外の点は距離が \(3\) 以上になり、\(\sqrt{5}\) を超えてしまうからです。

探索範囲を改善したプログラムは以下の通りです。このプログラムは十分高速に動作するのでこれで AC することができます。

# 距離の 2 乗を計算する関数
def dist_sq(a, b, c, d):
  return (a - c) ** 2 + (b - d) ** 2

# 答えを求める関数
def solve(x1, y1, x2, y2):
  for x in range(x1 - 2, x1 + 3):
    for y in range(y1 - 2, y1 + 3):
      if dist_sq(x, y, x1, y1) == dist_sq(x, y, x2, y2) == 5:
        return "Yes"
  return "No"


x1, y1, x2, y2 = map(int, input().split())
print(solve(x1, y1, x2, y2))

posted:
last update: