C - 終電に間に合え! / Catch the Last Train! 解説 by admin
Gemini 3.0 Flash (Thinking)概要
高橋君が「全力ダッシュ」を最適なタイミングで合計 \(K\) 秒間使い、駅(座標 \(G\))に到着する最短時間が、終電が駅に到着する時間以下であるかを判定する問題です。
考察
この問題を解くためには、「終電が駅に到着する時間」と「高橋君が駅に到着する最短時間」をそれぞれ求め、比較する必要があります。
1. 終電が駅に到着する時間 \(T_M\)
終電は現在座標 \(M\) にあり、毎秒 \(V\) の速度で座標 \(G\) に向かっています。 終電が駅に到着するまでの距離は \(M - G\) なので、到着時間は以下のようになります。 $\(T_M = \frac{M - G}{V}\)$
2. 高橋君が駅に到着する最短時間 \(T_T\)
高橋君は全力ダッシュ(速度 \(D\))を最大 \(K\) 秒間使えます。それ以外の時間は通常速度(速度 \(1\))で移動します。 時間を最短にするには、できるだけ「速度が速い状態」で距離を稼ぐのが最善です。つまり、全力ダッシュを可能な限り(最大 \(K\) 秒間)使うのが最適です。
ここで、全力ダッシュで進める距離 \(K \times D\) が、駅までの距離 \(G\) より大きいかどうかで場合分けが発生します。
ケースA:\(K \times D \ge G\) のとき ダッシュだけで駅に到達できます。最短時間 \(T_T\) は、距離 \(G\) を速度 \(D\) で割った値です。 $\(T_T = \frac{G}{D}\)$
ケースB:\(K \times D < G\) のとき \(K\) 秒間フルでダッシュしても駅に届かないため、残りの距離を通常速度で歩く必要があります。 ダッシュで進む距離は \(K \times D\)、残りの歩く距離は \(G - (K \times D)\) です。 $\(T_T = K + \frac{G - (K \times D)}{1} = G - K(D - 1)\)$
3. 判定式の変形(浮動小数点数誤差の回避)
条件 \(T_T \le T_M\) をそのまま計算すると、割り算によって小数の誤差が生じる可能性があります。競技プログラミングでは、分母を払って整数のみの比較に直すのが鉄則です。
- ケースAの判定式: \(\frac{G}{D} \le \frac{M - G}{V} \iff G \times V \le (M - G) \times D\)
- ケースBの判定式: \(G - K(D - 1) \le \frac{M - G}{V} \iff (G - K(D - 1)) \times V \le M - G\)
アルゴリズム
- 入力値 \(G, M, D, K, V\) を受け取る。
- \(K \times D\) と \(G\) を比較して、高橋君が駅に着くまでの移動パターンを判定する。
- 上記の考察に基づき、整数範囲での比較演算を行い、条件を満たせば
Yes、そうでなければNoを出力する。
計算量
- 時間計算量: \(O(1)\)
- 単純な四則演算と条件分岐のみで計算可能です。
- 空間計算量: \(O(1)\)
- 入力値を保持する変数以外のメモリは使用しません。
実装のポイント
大きな数への対応: \(M\) が最大 \(10^{15}\) と非常に大きいため、Pythonなどの多倍長整数を扱える言語以外では、64bit整数型(C++なら
long long)を使用する必要があります。誤差の回避: 考察で述べた通り、割り算(
/)を避け、掛け算(*)を用いた比較を行うことで、浮動小数点数による誤差を完全に防ぐことができます。ソースコード
import sys
def solve():
# 標準入力から全ての値を読み込む
input_data = sys.stdin.read().split()
if not input_data:
return
# 各変数を整数として取得
# G: 駅の座標
# M: 終電の初期座標
# D: 全力ダッシュ時の速度倍率
# K: 全力ダッシュ可能時間(秒)
# V: 終電の速度
G = int(input_data[0])
M = int(input_data[1])
D = int(input_data[2])
K = int(input_data[3])
V = int(input_data[4])
# 高橋君は座標0からGへ、終電は座標MからG(およびその先)へ向かう。
# 終電が駅(座標G)に到着する時間を T_M とすると、 T_M = (M - G) / V。
# 高橋君が駅(座標G)に到着する最短時間を T_T とすると、
# 高橋君が終電に間に合う条件は T_T <= T_M である。
# この条件式は、分母を払って V * T_T <= M - G と書き換えられる。
# 高橋君の最短時間 T_T を求める:
# 全力ダッシュを t 秒使うとすると、進む距離は t*D + (T_T - t)*1 = G。
# これを変形すると T_T = G - t*(D - 1) となる。
# T_T を最小化するには、ダッシュ時間 t を最大化すればよい。
# ただし、制約として t <= K かつ t*D <= G (駅を通り過ぎない範囲でダッシュする)がある。
# つまり、最適なダッシュ時間 t は min(K, G / D) である。
if K * D >= G:
# 全力ダッシュを t = G / D 秒使うことで、最短時間 T_T = G / D で駅に到達できる。
# 判定式: V * (G / D) <= M - G => V * G <= (M - G) * D
if V * G <= (M - G) * D:
print("Yes")
else:
print("No")
else:
# 全力ダッシュ可能時間を全て使い切り、残りの距離を通常速度で移動する。
# t = K, T_T = G - K * (D - 1)
# 判定式: V * (G - K * (D - 1)) <= M - G
if V * (G - K * (D - 1)) <= M - G:
print("Yes")
else:
print("No")
if __name__ == '__main__':
solve()
この解説は gemini-3-flash-thinking によって生成されました。
投稿日時:
最終更新: