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

abc320 AtCoder

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

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

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

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

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

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

AtCoder Beginner Contest 320

A問題:Leyland Number

A – Leyland Number

問題(要約)

与えられた正整数 A と B を使用して、AB + BA の値を計算し、その結果を出力するプログラムを作成してください。

解答

# スペースで区切られた2つの整数を入力として受け取り、それぞれaとbに代入します。
a, b = map(int, input().split())

# a^b + b^a の値を計算し、結果を出力します。
print(a**b + b**a)
  1. a, b = map(int, input().split()):
    • 入力を受け取ります。
    • input() 関数はユーザーからのテキスト入力を受け取ります。
    • split() メソッドは、受け取ったテキストをスペースで区切り、それをリストに変換します。
    • map(int, ...) はリスト内の各要素を整数に変換します。
    • 最終的に、2つの整数を ab に代入します。これらの整数は、ユーザーが入力した正の整数です。
  2. print(a**b + b**a):
    • ab を使用して、指数の計算を行います。
    • a**b は a の b 乗を計算し、b**a は b の a 乗を計算します。
    • それらの結果を足し合わせ、最終的な結果を画面に表示します。

B問題:Longest Palindrome

B – Longest Palindrome

問題(要約)

与えられた文字列 S から、連続する部分文字列の中で最も長い回文の長さを見つける問題です。必ず回文の部分文字列が存在します。

解答

与えられた文字列 S から最長の回文の長さを求めるために、ネストしたループ(二重ループ)と回文の判定関数を使用します。

# 回文の単語を判定する関数を定義します。
def is_palindrome_word(word):
    return word == word[::-1]

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

# 最長回文の長さを格納する変数を初期化します。
maxLen = 1

# 文字列 S をループで走査します。
for i, s in enumerate(S):
    for j in range(i + 1, len(S)):
        # S[i:j+1] が回文かどうかを is_palindrome_word 関数を使って判定します。
        if is_palindrome_word(S[i:j + 1]):
            # もし回文であれば、その長さを計算し、現在の最長回文の長さと比較します。
            maxLen = max(maxLen, j + 1 - i)

# 最長回文の長さを出力します。
print(maxLen)

以下詳細

  1. 文字列 S を入力として受け取ります。
  2. maxLen という変数を初期化し、最長回文の長さを 1 で設定します。なぜなら、どの文字も単独でも回文とみなされるためです。
  3. enumerate(S) を使用して文字列 S 内の各文字 s とそのインデックス i に対するループを開始します。
  4. ネストしたループを使って、文字列 S 内のすべての部分文字列について検討します。この内側のループは、i から len(S) までの範囲で実行されます。
  5. S[i:j+1] は、文字列 S 内の部分文字列で、これを is_palindrome_word 関数を呼び出して回文かどうかを判定します。
  6. もし S[i:j+1] が回文であれば、その長さ (j+1-i) を計算し、これを maxLen と比較して、より大きい場合は maxLen を更新します。これにより、現在の最長回文の長さが常に追跡されます。
  7. 最後に、最長回文の長さである maxLen を出力します。

C問題:Slot Strategy 2 (Easy) 

C – Slot Strategy 2 (Easy) 

問題(要約)

3つのリールから成るスロットがあり、各リールは数字のみからなる文字列で表されています。各リールにはボタンがあり、高橋君はスロットが回り始めてからちょうど t 秒後にボタンを1つ選んで押すか、何もしないことができます。リールは文字列の一部を表示する形で停止し、高橋君は全てのリールの表示が同じ文字になるように停止させたいと考えています。最終的に、全てのリールを停止させるまでにかかる最小の時間を求める問題です。もし目標を達成できない場合は-1を出力します。

解答

リールが3周するまでに数字が揃えられない場合は目標を達成できないため、秒数を3Mの期間のループを作り全検索を実施します (参考:AtCoderの楽な解法 )

# mを整数として入力として受け取ります。
m = int(input())

# 3つの文字列をリストSに格納します。
S = [input() for _ in range(3)]

# 最小のminSを3*m+1で初期化します。
minS = 3 * m + 1

# 3つのリールを回し始めてから、それぞれの停止位置に対してループを実行します。
for i in range(3 * m):
    for j in range(3 * m):
        # iとj が異なる事を確認します
        if i == j:
            continue
        for k in range(3 * m):
            # iとk, jとk が異なることを確認します。
            if i == k or j == k:
                continue
            # 3つのリールのそれぞれの位置で文字が一致する場合、minSを更新します。
            if S[0][i % m] == S[1][j % m] == S[2][k % m]:
                minS = min(minS, max(i, j, k))

# minSが初期値のままであれば、目標を達成できないため、-1を出力します。
if minS == 3 * m + 1:
    print(-1)
else:
    # それ以外の場合、最小の停止時間minSを出力します。
    print(minS)

以下詳細

  1. 最初に、整数 m を入力として受け取ります。これは各リールの文字列の長さを示します。
  2. 次に、3つの文字列をリスト S に格納します。これらは各リールの文字列です。3回ループを実行して3つの文字列を受け取ります。
  3. minS を 3*m+1 で初期化します。これは最小の停止時間を表す変数で、初期値は最大秒数 3M よりも大きい値に設定します。
  4. 3つのリールを回し始めてから、それぞれの停止位置に対して3重のループを使用してループします。i, j, k はそれぞれ3つのリールの停止秒数を表します。
  5. i, j, k が異なることを確認します。一度に1つのボタンしか押せないためです。
  6. 各リールの停止秒数から選ばれる文字が一致する場合、それぞれの停止秒数 i, j, k の最大値を計算し、最小の停止秒数 minS を更新します。
  7. 最終的に、minS が初期値のままであれば、目標を達成できないため、-1 を出力します。それ以外の場合、最小の停止時間 minS を出力します。

感想

今週も競技プログラミングに取り組みましたが、B問題までしか解けませんでした。しかし、一つ嬉しい変化がありました。

B問題が部分回文を探す問題だったのですが、以前であれば回文と聞いただけで思考停止してしまったでしょう。競プロの経験から、「回文を扱ったことがあるはずだ」と思い出し、前向きに問題に取り組むことができました。自分自身の成長を感じる小さな一歩でした(笑)。

C問題は解答の理解に時間がかかりましたが、考える時間も成長への投資だと信じています。次週も頑張り、新たな挑戦に取り組みたいと思います。緑コーダーへの道はまだまだ遠いですが、成長のプロセスを楽しんでいきます。

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

コメント

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