B - 山頂への登山 / Climbing to the Summit Editorial by admin
Gemini 3.0 Flash (Thinking)概要
高橋君が \(N\) 個の区間を順番に通過しながら、山頂を目指すシミュレーション問題です。各区間での体力の消費、バテ状態への変化、山小屋での回復という一連の処理を、ルールに従って正しく実行し、最終的な体力を求めます。
考察
この問題のポイントは、「バテた状態」への変化条件と、その後の影響を正確にシミュレーションすることです。
1. 状態の変化と不可逆性
高橋君の状態は「バテていない」から「バテた」への一方通行です。一度バテると、その後の山小屋で体力がどれだけ回復しても、消費体力が \(2 \times D_i\) になるペナルティは解除されません。
2. 処理の順序
各区間 \(i\) で行われる 3 つの手順の順序が非常に重要です。 1. 消費: 現在の状態に基づいて体力を減らす。 2. 判定: 消費後の体力が \(0\) 以下ならバテ状態にする。 3. 回復: 山小屋があれば回復する。
特に、「消費した直後に \(0\) 以下になったが、その後の回復で正に戻った」という場合でも、手順 2 の時点でバテ判定が行われるため、高橋君はバテた状態になります。 この順序を間違えると正しい結果が得られません。
3. 山小屋の管理
山小屋の情報 \((P_j, R_j)\) は、区間番号 \(P_j\) をキーとして効率的に参照する必要があります。\(N\) のサイズが最大 \(2 \times 10^5\) であるため、各区間の処理中に山小屋リストを全探索すると \(O(N \times M)\) となり、実行時間制限に間に合いません。配列や連想配列(辞書)を使って、特定の区間の後に山小屋があるかどうかを \(O(1)\) で判定できるように準備しておきます。
アルゴリズム
以下の手順でシミュレーションを行います。
- 準備:
- 各区間の難易度を配列 \(D\) に格納する。
- 長さ \(N+1\) の配列
hutsを用意し、huts[P_j] = R_jとして山小屋の回復量を記録しておく(山小屋がない場所は \(0\))。
- 初期化:
stamina = Sis_tired = False
- シミュレーション:
- \(i = 1\) から \(N\) まで順に繰り返す:
- 消費:
is_tiredが真ならstamina -= 2 * D[i]、偽ならstamina -= D[i]。 - 判定:
is_tiredが偽 かつstamina <= 0なら、is_tired = Trueに更新。 - 回復:
stamina += huts[i]。
- 消費:
- \(i = 1\) から \(N\) まで順に繰り返す:
- 出力:
- 最終的な
staminaを出力する。
- 最終的な
計算量
- 時間計算量: \(O(N + M)\)
- 入力の読み込みと山小屋データの格納に \(O(N + M)\) かかります。
- \(N\) 個の区間を 1 回ずつループで処理するため、シミュレーション部分は \(O(N)\) です。
- 空間計算量: \(O(N)\)
- 区間の難易度 \(D\) と山小屋の回復量
hutsを保持するために \(O(N)\) のメモリを使用します。
- 区間の難易度 \(D\) と山小屋の回復量
実装のポイント
大きな数値の扱い: 体力や難易度は最大 \(10^9\) であり、最終的な体力が非常に大きな負の値になったり、初期体力を大きく超えたりする可能性があります。Python では整数の大きさに制限がないため問題ありませんが、他の言語(C++ や Java など)を使用する場合は、64bit 整数型(
long longやlong)を使用する必要があります。入出力の高速化: \(N\) や \(M\) が大きいため、Python では
sys.stdin.read().split()などを用いて一括で入力を読み込むと実行時間を短縮できます。ソースコード
import sys
def solve():
# Read all input at once and convert to integers for efficiency
try:
data = list(map(int, sys.stdin.read().split()))
except EOFError:
return
if not data:
return
# N: number of segments, M: number of mountain huts, S: initial stamina
N = data[0]
M = data[1]
S = data[2]
# D: list of difficulties for each segment (D_1 to D_N)
# They are located from index 3 to 3 + N - 1 in the data list.
D = data[3 : 3 + N]
# huts: recovery amount at the end of each segment
# huts[i] stores the recovery amount R_j if a hut is located after segment i (P_j = i).
# Since P_j is between 1 and N-1, a list of size N+1 is sufficient.
huts = [0] * (N + 1)
# Offset where the hut information (P_j, R_j) begins
offset = 3 + N
for i in range(M):
p = data[offset + 2 * i]
r = data[offset + 2 * i + 1]
huts[p] = r
stamina = S
is_tired = False
# Simulate the process for each segment from 1 to N
for i in range(1, N + 1):
# difficulty of the current segment
d = D[i - 1]
# 1. Stamina consumption
if is_tired:
# If already tired, stamina consumption is doubled
stamina -= 2 * d
else:
# If not tired, stamina consumption is normal
stamina -= d
# 2. Fatigue check
# If stamina becomes 0 or less after consumption, the state changes to tired.
if stamina <= 0:
is_tired = True
# 3. Recovery at mountain hut (if any)
# Recovery occurs after the segment is passed and fatigue check is completed.
stamina += huts[i]
# Output the final remaining stamina
print(stamina)
if __name__ == "__main__":
solve()
この解説は gemini-3-flash-thinking によって生成されました。
posted:
last update: