こんにちは、こんぶちゃ(茶コーダー)です!
初心者視点から競プロAtCoderのABC332のA問題〜C問題の自身の解答と解答説明をしていきます。
まだまだ学習の身ですので、最適コードではない部分も多々あるかと思いますが、その部分は同じ学習者として温かい気持ちで応援&ご助言頂けば嬉しいです。
では早速行ってみましょう!
今回の参加コンテスト(ABC332)
A問題:Online Shopping
問題文(要約)
高橋君はAtCoder社のオンラインショップでN種類の商品を購入します。各商品は1からNまでの番号が付けられ、i番目の商品はPi円でQi個購入します。さらに、送料は購入した商品の合計金額がS円以上ならば0円、そうでなければK円かかります。高橋君が支払う金額を計算してください。
解答
# 入力から必要な情報を取得
n, s, k = map(int, input().split())
# 初期化:支払金額を格納する変数
ans = 0
# 商品ごとに処理
for _ in range(n):
# 商品の価格と個数を取得
p, q = map(int, input().split())
# 支払金額に商品価格 * 個数を加算
ans += p * q
# 支払金額が送料の条件を満たしているか判定
if ans >= s:
# 条件を満たしていれば、送料は0円として支払金額を出力
print(ans)
else:
# 条件を満たしていなければ、送料を加算して支払金額を出力
ans += k
print(ans)
解き方)
- 入力の取得:
n, s, k
を入力として受け取ります。これは商品の種類数、送料の条件、送料の金額です。
- 支払金額の計算:
- 商品ごとに
for
ループを回し、各商品の価格p
と個数q
を入力として受け取ります。 - 商品ごとの支払金額は
p * q
で計算され、これを変数ans
に加算していきます。
- 商品ごとに
- 送料の判定:
- 全ての商品の支払金額が送料条件
s
を満たしているかを判定します。 - 満たしていれば、送料は0円として
ans
をそのまま出力します。 - 満たしていなければ、送料
k
をans
に加算してから出力します。
- 全ての商品の支払金額が送料条件
B問題:Glass and Mug
問題(要約)
AtCoder社では、高橋君が持っている容量がG mlのグラスとM mlのマグカップを使って、K回の操作を行います。グラスとマグカップは最初どちらも空で、特定の条件に基づいて以下の操作が行われます。
- グラスがG mlの水で満たされている場合、グラスの水を捨てる。
- グラスがG ml未満で、かつマグカップが空の場合、マグカップを水で満たす。
- 上記の条件にも該当しない場合、マグカップからグラスに水を移す。この際、マグカップが空になるか、グラスがG mlになるまで繰り返す。
これらの操作をK回繰り返した後に、それぞれの容器に入っている水の量を求めてください。
解答
# 入力から必要な情報を取得
k, g, m = map(int, input().split())
# 初期化:グラスとマグカップに入っている水の量を格納する変数
glass, mug = 0, 0
# 操作をK回繰り返す
for _ in range(k):
# グラスがG mlに満たされている場合
if glass == g:
glass = 0
# グラスがG ml未満で、かつマグカップが空の場合
elif mug == 0:
mug = m
# 上記の条件にも該当しない場合、マグカップからグラスに水を移す
else:
# 移す水の量がマグカップに残っている水の量を超えないようにする
if mug - (g - glass) >= 0:
mug = mug - (g - glass)
glass = glass + (g - glass)
else:
# 移す水の量がマグカップに残っている水の量を超える場合、マグカップの水を全部移す
glass += mug
mug = 0
# 最終的なグラスとマグカップに入っている水の量を出力
print(glass, mug)
解き方)
ガラスに水が残っている場合に、移せれる量を考慮する必要があります。
- 入力の取得:
k, g, m
を入力として受け取ります。これは操作回数、グラスの容量、マグカップの容量です。
- 初期化:
glass
とmug
を0で初期化します。これはそれぞれグラスとマグカップに入っている水の量を表します。
- 操作を繰り返す:
for
ループを使って操作をK回繰り返します。- 各操作では、グラスがG mlに満たされている場合、グラスの水を捨てる (
glass = 0
)。 - グラスがG ml未満で、かつマグカップが空の場合、マグカップを水で満たす (
mug = m
)。 - 上記の条件にも該当しない場合、マグカップからグラスに水を移す。
- 移す水の量がマグカップに残っている水の量を超えないようにする。
- 移す水の量がマグカップに残っている水の量を超える場合、マグカップの水を全部移す。
- 最終的な水の量を出力:
glass
とmug
に入っている水の量を出力します。
C問題:T-shirts
問題(要約)
高橋君のN日間の予定が0, 1, 2のいずれかからなる文字列Sで与えられます。1日目の直前の時点で洗濯済みの無地のTシャツがM枚あります。各日の予定に基づき、以下の条件を満たすように行動できるように、高橋君はAtCoderのロゴ入りTシャツを何枚か購入することにしました。
- 食事に行く日には、無地のTシャツ1枚またはロゴ入りのTシャツ1枚を着用する。
- 競技プログラミングのイベントに行く日には、ロゴ入りのTシャツ1枚を着用する。
- 何の予定もない日にはTシャツを着用せず、その時点で着用済みのTシャツを全て洗濯する。洗濯したTシャツは翌日から着用できる。
- 一度着用したTシャツは次に洗濯するまで着用できない。
この条件を満たすために、高橋君が最低何枚のTシャツを購入する必要があるかを求める問題です。
解答
# 必要なライブラリをインポート
from collections import Counter
# 入力から必要な情報を取得
n, m = map(int, input().split())
S = input()
# 初期化:答えとなる変数を0で初期化
ans = 0
# 0を区切りとして分割し、各部分について処理
for s in S.split("0"):
# 各部分の数字の出現回数をカウント
numCnt = Counter(s)
# 答えを更新:ロゴ入りTシャツを購入する必要がある日数を計算
ans = max(ans, numCnt['2'] + max(0, numCnt['1'] - m))
# 結果を出力
print(ans)
解き方)
何も予定のない0の時でリセットされることに着目し、0になるまでを一区切りと考えています。
- 入力の取得:
n, m
はそれぞれ日数と、1度の洗濯できるロゴ入りTシャツの枚数を表します。S
は高橋君のN日間の予定を表す文字列です。
- 初期化:
ans
は答えとなる変数で、最初は0で初期化されます。
- 0で分割し各部分に対する処理:
S.split("0")
を使って、0で文字列を分割し、各部分に対して以下の処理を行います。numCnt
は各部分内の数字の出現回数をカウントするための辞書です。
- ロゴ入りTシャツの購入必要枚数の計算:
numCnt['2']
は競技プログラミングのイベントに行く日の回数を表します。numCnt['1'] - m
は食事に行く日の回数から1度の洗濯できる回数を引いた値で、これが0より小さい場合は購入必要なし、0以上の場合はその数がロゴ入りTシャツの購入必要な日数です。
- 最大値の更新:
- 各部分に対する購入必要日数を計算し、それを
ans
と比較して、より大きい方をans
に代入します。
- 各部分に対する購入必要日数を計算し、それを
- 結果の出力:
- 最終的な答えを出力します。
感想
C問題まで解けました!B問題で少し苦戦しましたが、最終的には乗り越えることができました!^^
B問題は、条件分岐の基本問題で、ガラスに水が残っている場合も含めて条件を考える必要がありました。ここに気づくまでに2回誤り、計30分悩んでしまいました。しかし、最終的には問題文を注意深く読み、一つずつ順番に実装することで解決できました。この問題から問題文の重要性を再認識しました。
一方で、C問題は比較的スムーズに解けました。何もない日の”0″にリセットできることに着目し、split
関数を使って範囲を分割することで問題文を単純化できました。
RatingはB問題で苦戦したこともあり少し下がってしまいました(542点)。来週も引き続き頑張ります!
それでは、良い競プロライフを~!(*^▽^)/
コメント