【ABC315】競プロのA-C問題を40代サラリーマンがPython解説!初心者にもわかりやすく

abc315 AtCoder

こんにちは、こんぶちゃ(茶コーダー)です!

初心者視点から競プロAtCoderのABC315のA問題〜C問題の自身の解答と解答説明をしていきます。

こんな人にオススメしたい
  • 競技プログラミング初心者で、問題の解き方がわからない方
  • AtCoderの公式解説は読んだが、内容が理解できなかった方
  • Pythonでの解法を知りたい方

まだまだ学習の身ですので、最適コードではない部分も多々あるかと思いますが、その部分は同じ学習者として温かい気持ちで応援&ご助言頂けば嬉しいです。

では早速行ってみましょう!

今回使用している機能・アルゴリズム
  • 並び替え (リストのインデックス番号)        ・・・ 問題C

今回の参加コンテスト(ABC315)

AtCoder Beginner Contest 315

A問題:tcdr

A – tcdr

問題(要約)

英小文字からなる文字列Sが与えられます。Sから a, e, i, o, u を取り除いた文字列を出力してください

解答

考え方 )

母音のリストaeiou = [‘a’, ‘e’, ‘i’, ‘o’, ‘u’] を準備し、文字列Sを一文字づつ確認します

詳細はコードの中にコメントを参照してください

# ユーザーからの入力を受け取ります
S = input()

# 母音のリストを定義します
aeiou = ['a', 'e', 'i', 'o', 'u']

# 結果を格納するためのリストを初期化します
ans = []

# 文字列S内の各文字に対して処理を行います
for s in S:
    # もし文字sが母音のリストaeiouに含まれていなければ(子音であれば)実行されます
    if s not in aeiou:
        # 子音をansリストに追加します
        ans.append(s)

# ansリストの文字をスペースなしで表示します
# アスタリスク(*)は、リストの要素を展開して表示します
# ここでは、ansリストの要素がprint()の引数として使われ、連結されて表示されます
print(*ans, sep="")

別解)

上記と同じ内容を下記一文で記載することもできます

# ユーザーからの入力を受け取り、1文字ずつリスト内包表記で処理します
# 母音('a', 'e', 'i', 'o', 'u')に含まれていない文字だけを取り出して新たなリストを作成し、その内容を出力します

print(*[s for s in input() if s not in ['a', 'e', 'i', 'o', 'u']], sep='')

B問題:The Middle Day

B – The Middle Day

問題(要約)

AtCoder国の暦では、一年はMか月からなり、各月はそれぞれ1からD1日までの日で構成されています。AtCoder国の一年の日数の合計(D1 + D2 + … + DM)は奇数です。真ん中の日は合計日数の半分((D1 + D2 + … + DM + 1) / 2)に対応します。このとき、真ん中の日は何番目の月の何番目の日に該当するかを求めてください。

解答

考え方)

月ごとの日数の合計を計算し、真ん中の日(合計日数の半分)が何番目の月の何番目の日に該当するかを求めます

# 月の数を入力します
m = int(input())

# 各月の日数をリストとして入力します
D = list(map(int, input().split()))

# 真ん中の日を計算します
mid = (sum(D) + 1) // 2

# 各月の日数を順に処理します
for i, d in enumerate(D, start=1):
    # もし真ん中の日が現在の月の日数以下であれば、その月と日に該当します
    if mid - d <= 0:
        exit(print(i, mid))  # 月の番号と日にちを出力して終了します
    else:
        mid -= d  # 真ん中の日がまだ次の月まで達していない場合、日数を減らします

以下詳細

  1. 月の数 M を入力を受け取ります。
  2. 各月の日数 D を入力からリストとして受け取ります。
  3. 全ての月の日数の合計を計算して、合計日数の半分を mid に設定します。
  4. 各月の日数とその月の番号を enumerate 関数を使って各月の日数とその月の番号を同時に取り扱います。
  5. もし mid – d が現在の月の日数以下であれば、その月と日にちが真ん中の日に該当します。その月の番号と日にちを出力してプログラムを終了します。
  6. もし mid – d が0以上の場合、真ん中の日が次の月まで達していないため、次の月に進みます。mid を現在の mid – d の値で更新し、次の月の日数を調べるための準備をします。

C問題:Flavors

C – Flavors

問題(要約)

N個のアイスクリームがあり、各アイスクリームの味はFiで、美味しさはSi(ただし、Siは偶数)です。あなたはN個のアイスクリームの中から2つを選んで食べることにします。選んだアイスクリームの味をsとtとすると、満足度は以下のように定義されます。

  • もしsとtの味が異なる場合、満足度はs + tです。
  • もしsとtの味が同じ場合、満足度はs + t/2です。

このとき、達成可能な最大の満足度を求めてください。

解答

考え方)

  1. アイスクリームの美味しさと味をリストに格納し、美味しさでソートします。
  2. 最も美味しいアイスクリームを選び、下記2通りを考えます
    • tmp1 = 最も美味しいアイスクリーム + 異なる味のアイスクリーム
    • tmp2 = 最も美味しいアイスクリーム + 同じ味のアイスクリーム (2番目限定)
  3. 上記 tmp1 と tmp2 の最大値を出力します。
n = int(input())  # アイスクリームの数

F, S = [], []  # 味と美味しさを格納するリスト

# アイスクリームの味と美味しさを入力し、リストに追加していく
for _ in range(n):
    f, s = map(int, input().split())
    F.append(f)
    S.append(s)

# 美味しさを降順にソートし、そのインデックスのリストを作成する
sorted_indices = sorted(range(n), key=lambda i: S[i], reverse=True)

# 最初に選ぶアイスクリームの美味しさと味を取得する
tasts = S[sorted_indices[0]]
flavor = F[sorted_indices[0]]
tmp1, tmp2 = S[sorted_indices[0]], S[sorted_indices[0]]

# アイスクリームを選ぶ処理を開始
for idx, i in enumerate(sorted_indices[1:], start=1):
    if flavor != F[i]:  # 味が異なるアイスクリームが見つかった場合
        tmp1 += S[i]
        break
    elif idx == 1:  # 味が同じアイスクリームが2つ目に見つかった場合
        tmp2 += S[i] // 2
print(max(tmp1, tmp2))  # 最大の満足度を出力

以下詳細

  1. n を入力して、アイスクリームの数を取得します。
  2. FS という2つのリストを用意します。これらはアイスクリームの味と美味しさを格納するためのものです。
  3. n 回のループを使って、各アイスクリームの味と美味しさを入力し、それぞれのリストに追加していきます。
  4. 美味しさ S を降順(美味しさが高い順) にソートするため、各アイスクリームの美味しさのインデックスを sorted_indices に格納します。
  5. 最も美味しいアイスクリームを最初に選び、その美味しさと味を tastsflavor に格納します。また、tmp1tmp2S の最大の美味しさで初期化します。
  6. sorted_indices リストの残りのアイスクリームを順に調べていきます。アイスクリームの味が異なる場合、tmp1に美味しさを加算します。
  7. 2つ目に美味しいアイスクリームの味が同じ場合、2つ目のアイスクリームの美味しさを半分としてtmp2に加算します。
  8. 最終的に、tmp1tmp2 の中から最大の満足度を取り、結果を出力します。

感想

今回のコンテストではA問題とB問題はスムーズに解決。そして、C問題にも挑戦し、なんと40分以内で解けた瞬間、達成感が溢れました!

しかし、自信満々で提出したものの、残念ながら不正解(´;ω;`)。自身の方法が正しいと信じて、細かな修正を行いながら1時間が経過しました。結局問題を解決することはできず、ショックで胸が痛みました(´;д;`)

ふて寝ならず、ふて漫画を楽しんで気分転換。最近は「東京リベンジャーズ」が私の癒しの時間です(^◡^)。

うまくいく時もあれば、うまくいかない時もある。しかし、大事なのは淡々と挑戦を続けること(*1)。

これからも難しい問題に立ち向かいながら、着実に成長していくことが大切だと思います。来週のコンテストも楽しみながら挑戦していきます!

それでは、良い競プロライフを~!(*^▽^)/

*1 小林正観さんの「人生は4つの「おつきあい」」に影響を受けました

コメント

タイトルとURLをコピーしました