こんにちは、こんぶちゃ(茶コーダー)です!
初心者視点から競プロAtCoderのABC330のA問題〜C問題の自身の解答と解答説明をしていきます。
まだまだ学習の身ですので、最適コードではない部分も多々あるかと思いますが、その部分は同じ学習者として温かい気持ちで応援&ご助言頂けば嬉しいです。
では早速行ってみましょう!
今回の参加コンテスト(ABC330)
A問題:Counting Passes
問題文
N 人の人 1,2,…,N がある試験を受け、人 i は Ai 点を取りました。
この試験では、 L 点以上を取った人のみが合格となります。N 人のうち何人が合格したか求めてください。
解答
# 入力から n(人数)と l(合格基準点)を受け取る
n, l = map(int, input().split())
# 各人の点数を受け取り、リスト A に格納する
A = list(map(int, input().split()))
# 合格者の数をカウントする変数を初期化
ans = 0
# 各人の点数に対して合格基準を満たすか判定し、合格者の数をカウント
for a in A:
if a >= l:
ans += 1
# 合格者の数を出力
print(ans)
解き方)
- 入力から人数 n と合格基準点 l を受け取ります。
- 各人の点数をリスト A に格納します。
- 各人の点数に対して、合格基準 l 以上かどうかを判定します。
- 合格基準を満たす人の数をカウントして、最終的な結果を出力します。
別解) 内包表記を使ってfor文とif文をまとめています。
# 入力から n(人数)と l(合格基準点)を受け取る
n, l = map(int, input().split())
# 各人の点数を受け取り、その中で合格基準を満たす人数を数えて出力する
print(len([x for x in list(map(int, input().split())) if x >= l]))
B問題:Minimize Abs 1
問題(要約)
長さ N の整数列 A と整数 L, R が与えられたときに、各要素について条件を満たす整数 X を求める。条件は以下の2つです:
- LからRの範囲内にある(L≤X_i≤R)
- L以上R以下の任意の整数 Y に対して、|X_i – A_i| ≤ |Y – A_i| を満たす
これらの条件を満たす整数 X_i を求めてください。
解答
問題文から、Ai が 整数 L〜R に対して最小になるように設定すれば、Xiが最小になります。
# 入力から整数 n, l, r を取得
n, l, r = map(int, input().split())
# 整数列 A を取得し、リストに変換
A = list(map(int, input().split()))
# 結果を格納する空のリストを作成
ans = []
# 整数列 A の各要素に対して処理を行う
for a in A:
# 条件に基づいて X_i を求めて結果リストに追加
if a < l:
ans.append(l)
elif l <= a <= r:
ans.append(a)
else:
ans.append(r)
# 結果リストをスペース区切りで出力
print(*ans)
解き方)
- 入力の取得:
- 最初の行で、空白区切りの整数 n, l, r を取得しています。n は整数列 A の長さであり、l と r は条件式に利用される整数です。
- 次の行で、空白区切りの整数列 A をリストとして取得しています。
- 条件に基づいた X_i の計算:
for
ループでは、整数列 A の各要素 a について以下の条件に基づいて X_i を計算しています。if-elif-else
条件文を使って、a が l より小さい場合は l を、a が l 以上かつ r 以下の場合はそのままの値を、a が r より大きい場合は r を X_i として選択しています。- 計算された X_i は
ans
リストに追加されます。
- 結果の出力:
print(*ans)
を使って、リストans
の要素をスペース区切りで出力しています。これにより、各要素の X_i が出力されます。
C問題:Minimize Abs 2
問題(要約)
正整数 D が与えられます。
非負整数 x,y に対する ∣x2+y2−D∣ の最小値を求めてください。
解答
import math
# 正整数 D を入力として受け取る
d = int(input())
# x, y の範囲を制限するための side を計算
side = int(math.sqrt(d) + 1)
# 答えを無限大で初期化
ans = float('inf')
# x の範囲を探索
for x in range(side):
# y の範囲を計算(0 以上の値に制限)
y_side = int(math.sqrt(max(0, d - x**2)))
# y の範囲を探索
for y in range(y_side, y_side + 2):
# 式 |x^2 + y^2 - d| の値を計算し、答えの最小値を更新
ans = min(ans, abs(x**2 + y**2 - d))
# 最小値を出力
print(ans)
解き方)
- 範囲の制約計算:
math.sqrt(d)
はd
の平方根を計算し、int
を使って整数部分を取得します。これがside
となり、x
やy
の範囲を制約するために使われます。
- 最小値の初期化:
ans = float('inf')
でans
を無限大で初期化します。これは後で最小値を更新するために使われます。
- x の範囲の探索:
for x in range(side):
で x の範囲を探索します。
- y の範囲の計算:
y_side = int(math.sqrt(max(0, d - x**2)))
で y の範囲を計算します。max(0, d - x**2)
は x^2 を引いた残り部分が負にならないようにするためのものです。
- y の範囲の探索:
for y in range(y_side, y_side + 2):
で y の範囲を探索します。y_side から y_side + 1 までの 2 つの値を試すことで、y を探索しています。
- 式の計算と最小値の更新:
ans = min(ans, abs(x**2 + y**2 - d))
で式|x^2 + y^2 - d|
の値を計算し、これが現在の最小値ans
よりも小さければans
を更新します。
- 最小値の出力:
- 最終的に
print(ans)
で最小値を出力します。
- 最終的に
感想
今週もC問題まで解けました!B, C問題では苦労しましたが、最終的に解決することができました! ^^ !
B問題では、問題文の理解に苦労しました。何度も問題と例題を繰り返し読み返し、最終的には要点を理解できました。コードの実装は複雑ではありませんでしたが、読解力が試される問題でした。
C問題も難航しました。最初は愚直に全検索で実装しましたが、TLE(制限時間超過)になりました。そこで数学的な観点を用いて検索時間を削減しましたが、特定条件で不正解となりました。最終的には検索幅を一部増やして、すべての場合をカバーできるようにしてやっとAC(正解)になりました。
今回の問題は、B・C問題の難易度が私にとって高かったですが、諦めずに挑戦し、最終的に解答に辿り着けたことが非常に嬉しいです。
Ratingは維持できました(551点)。来週も引き続き頑張ります!
それでは、良い競プロライフを~!(*^▽^)/
コメント