C - 期末テストのやり直し / Make-Up Exam Editorial by admin
Claude 4.6 Opus (Thinking)概要
高橋君がちょうど1科目だけ受け直して得点を自由に変えられるとき、高橋君と青木君の合計得点の差(高橋 − 青木)を最大化する問題です。
考察
まず、受け直しをしない場合の合計得点の差は次のように計算できます。
\[\text{total\_diff} = \sum_{i=1}^{N} A_i - \sum_{i=1}^{N} B_i\]
次に、高橋君が科目 \(i\) を受け直す場合を考えます。科目 \(i\) の得点を \(A_i\) から新しい点数 \(X\)(\(0 \leq X \leq P_i\))に変更すると、合計得点の差は:
\[\text{total\_diff} - A_i + X\]
になります。これを最大化するには \(X\) をできるだけ大きくすればよいので、\(X = P_i\)(満点)にするのが最適です。
このとき、科目 \(i\) を受け直すことによる「差の増加量(利得)」は:
\[\text{gain}_i = P_i - A_i\]
となります。これは「科目 \(i\) であとどれだけ伸ばせるか」、すなわち 伸びしろ に相当します。
具体例: \(N = 2\)、\(P = [100, 50]\)、\(A = [80, 10]\)、\(B = [70, 60]\) の場合
- 受け直しなしの差: \((80 + 10) - (70 + 60) = -40\)
- 科目1を受け直し: 利得 \(= 100 - 80 = 20\)、差 \(= -40 + 20 = -20\)
- 科目2を受け直し: 利得 \(= 50 - 10 = 40\)、差 \(= -40 + 40 = 0\)
科目2の方が伸びしろが大きいので、科目2を受け直すのが最適です。
重要な気づき: 全科目の中から \(P_i - A_i\) が最大の科目を1つ選べばよいだけなので、全探索で十分効率的です。
アルゴリズム
- 入力を読み込む。
- 現在の合計得点の差 \(\text{total\_diff} = \sum A_i - \sum B_i\) を計算する。
- 各科目 \(i\) について利得 \(P_i - A_i\)(伸びしろ)を計算し、その最大値 \(\text{best\_gain}\) を求める。
- 答えは \(\text{total\_diff} + \text{best\_gain}\) である。
計算量
- 時間計算量: \(O(N)\) — 合計の計算と最大値の探索がそれぞれ \(O(N)\)
- 空間計算量: \(O(N)\) — 配列 \(P, A, B\) の格納
実装のポイント
高橋君は得点を下げることもできますが、差を最大化したいので、必ず満点を取るのが最適です。そのため、得点を下げるケースは考慮不要です。
\(P_i\) や得点の値が最大 \(10^9\)、科目数が最大 \(2 \times 10^5\) なので、合計値は最大で \(2 \times 10^{14}\) 程度になります。Python では整数のオーバーフローを気にする必要はありませんが、C++ などでは
long longを使う必要があります。「受け直した結果、元の点数と同じ点数になることもあり得る」とありますが、これは \(P_i - A_i = 0\) の場合に相当し、利得が 0 になるだけなので自然に処理されます。
ソースコード
import sys
def main():
input_data = sys.stdin.read().split()
idx = 0
N = int(input_data[idx]); idx += 1
P = [int(input_data[idx + i]) for i in range(N)]; idx += N
A = [int(input_data[idx + i]) for i in range(N)]; idx += N
B = [int(input_data[idx + i]) for i in range(N)]; idx += N
total_diff = sum(A) - sum(B)
# For each subject i, if Takahashi retakes it, he can change A[i] to any value in [0, P[i]].
# The new difference = total_diff - A[i] + new_score
# To maximize, set new_score = P[i], so gain = P[i] - A[i]
# We want to maximize (P[i] - A[i]) over all i.
best_gain = max(P[i] - A[i] for i in range(N))
print(total_diff + best_gain)
main()
この解説は claude4.6opus-thinking によって生成されました。
posted:
last update: