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

AtCoder

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

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

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

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

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

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

AtCoder Beginner Contest 336

A問題:Long Loong

A – Long Loong

問題文

正の整数 X について、レベル X の 龍文字列 とは、1 個の LX 個の o1 個の n1 個の g をこの順に並べた長さ (X+3) の文字列です。

正の整数 N が与えられるので、レベル N の龍文字列を出力してください。
大文字と小文字は区別されることに注意してください。

解答

print('L' + 'o' * int(input()) + 'ng')

考え方)

下記の処理を1文で処理を行っています。受け取った入力を数字に変えつつ、print文に直接組み込んでいます。

  1. input() 関数を使用してユーザーから整数 N を受け取ります。
  2. 受け取った整数 N を int() 関数を使って整数型に変換します。
  3. 'L''ng' の文字列を連結し、その間に 'o' を N 個連結しています。
  4. 得られた文字列を print() 関数を使用して出力します。

B問題:CTZ

B – CTZ

問題

正の整数 X に対して、X を 2 進表記したときに 末尾 に連続する 0 の個数(の最大値)を ctz(X) で表します。
ただし、X を 2 進表記したとき末尾が 1 ならば ctz(X)=0 です。

正の整数 N が与えられるので、ctz(N) を出力してください。

解答

n = int(input())  # 整数 N を入力
bin_str = bin(n)  # N を2進数表記に変換し、文字列として取得
reversed_bin_str = list(reversed(bin_str))  # 2進数表記を逆順にしたリストを作成

ans = 0  # 末尾の0の個数をカウントする変数
for b in reversed_bin_str:
    if b == '0':
        ans += 1
    else:
        break  # 1を見つけたらループを終了

print(ans)  # 末尾の0の個数を出力

解き方)

pythonの2進数表記変換のbin関数を用いています。bin関数は、文字型で返してくれるため、文字のままの扱いでゼロの数を数えています。

  1. n = int(input()):ユーザーから整数 N を入力します。
  2. bin(n) を使用して、整数 N を2進数表記に変換し、文字列として bin_str に格納します。
  3. reversed(bin_str) を使用して、2進数表記を逆順にしたリスト reversed_bin_str を作成します。これにより、末尾から数えることができます。
  4. ans を初期化して、末尾の0の個数をカウントする変数を用意します。
  5. リスト reversed_bin_str を反復処理し、末尾から0の個数をカウントします。1を見つけたらループを終了します。
  6. 最終的な末尾の0の個数を ans から取得し、それを出力します。

C問題:Even Digits

C – Even Digits

問題

非負整数 n が次の条件を満たすとき、n を 良い整数 と呼びます。

  • n を 10 進法で表したときに、偶数の数字 (0,2,4,6,8) のみが登場する。

例えば 068 および 2024 は良い整数です。 

整数 N が与えられます。良い整数のうち小さい方から N 番目の整数を求めてください。

解答

def decimal_to_quinary(decimal_number):
    # 10進数を5進数に変換する関数
    if decimal_number == 0:
        return '0'  # 0の場合はそのまま0を返す

    quinary = ''  # 5進数を構築するための空の文字列

    while decimal_number > 0:
        remainder = decimal_number % 5  # 5で割った余りを計算
        quinary = str(remainder) + quinary  # 余りを5進数の左側に追加
        decimal_number //= 5  # 10進数を5で割る

    return quinary

def make_good_num(qui_num):
    # 5進数を"良い整数"に変換する関数
    trans_num = {'0':'0', '1':'2','2':'4','3':'6','4':'8'}
    # 5進数の各桁を対応する偶数に変換
    return "".join([trans_num[w] for w in qui_num])  # 変換した偶数を結合して返す

#    上記のreturnの処理を内包表記を使わない場合
#    good_num =""
#    for w in qui_num:
#        good_num +=trans_num[w]
#    return good_num

# メイン処理
n = int(input("Nを入力してください: "))  # ユーザーからの入力
quinary_num = decimal_to_quinary(n-1)  # 10進数を5進数に変換
ans = make_good_num(quinary_num)  # 5進数を"良い整数"に変換
print(ans)  # 結果の出力


解き方)

今回の問題では、偶数の(0, 2, 4, 6, 8)が良い数字であるため、この数字を小さい順に組み合わせることにより、N番目の数字(文字列型)を作っていきます。主に次の2工程で数字を求めていきます。

  • 与えられた数字を5進数に変換:5進数に変換することにより、各桁が0~4の5つの数字だけで表せることができるようになります。
  • 5進数の数字を偶数に変換:5進数の数字を求めたい偶数の数字に割り当てます。
    例) 5進数の0 -> 10進数の0, 5進数の1 -> 10進数の2, …, 5進数の4 -> 10進数の8

また、5進数に与える数字を n-1 していますが、0は1番目の数字であり、この番号を考慮しています。

下記がコードの詳細です。

  1. decimal_to_quinary関数:
    • decimal_numberを5進数に変換します。
    • 0が入力された場合、5進数も0となります。
    • 10進数を5で割り、余りを文字列の前に追加していきます。
  2. make_good_num関数:
    • 5進数を”良い整数”に変換します。
    • trans_num辞書を使って、各5進数の桁を対応する偶数に変換します。
    • コメントアウトされた部分は、別の方法で同じ操作を行う例です。
  3. メイン処理:
    • 入力から整数Nを入力して受け取ります。
    • n-1decimal_to_quinaryに渡して5進数に変換し、その結果をmake_good_numに渡して”良い整数”に変換します。
    • 最後に、求めた”良い整数”を出力します。

感想

今回は、B問題までしか解けなかったので、少し悔しいですね。

このコンテストでは、N進数や文字列を扱う問題が目立ちました。

A問題は、特定の文字の繰り返しを扱う問題で、比較的簡単でした。ただ、文字列の組み合わせを ‘+’ 記号で表現する部分には、少し戸惑いました(笑)。

B問題では、2進数への変換と文字列処理を駆使して、数字を逆順に数える問題に挑戦しました。最初は戸惑いましたが、ネットで2進数の変換方法を調べ、すぐに解決策を見つけました。ただ、bin()関数の使い方をすぐに忘れてしまうのが課題です。

C問題は、偶数のみを使って特定の数字を作る問題でした。数字の組み合わせについては考えが及んだのですが、具体的な実装方法が思いつかず、時間切れになってしまいました。5進数を利用するアプローチは斬新で、他の問題にも応用できそうだと感じました。

結果としてはB問題までの解答で、Ratingが15ポイント下がり、541になりましたが、とても勉強になるコンテストだったと思います。これからも楽しみながら、競技プログラミングに挑戦し続けたいと思います。

それでは、皆さんも競プロライフを楽しんでくださいね!(*^▽^)/

コメント

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