こんにちは、こんぶちゃ(茶コーダー)です!
初心者視点から競プロAtCoderのABC336のA問題〜C問題の自身の解答と解答説明をしていきます。
まだまだ学習の身ですので、最適コードではない部分も多々あるかと思いますが、その部分は同じ学習者として温かい気持ちで応援&ご助言頂けば嬉しいです。
では早速行ってみましょう!
今回の参加コンテスト(ABC336)
A問題:Long Loong
問題文
正の整数 X について、レベル X の 龍文字列 とは、1 個の L
, X 個の o
, 1 個の n
, 1 個の g
をこの順に並べた長さ (X+3) の文字列です。
正の整数 N が与えられるので、レベル N の龍文字列を出力してください。
大文字と小文字は区別されることに注意してください。
解答
print('L' + 'o' * int(input()) + 'ng')
考え方)
下記の処理を1文で処理を行っています。受け取った入力を数字に変えつつ、print文に直接組み込んでいます。
input()
関数を使用してユーザーから整数 N を受け取ります。- 受け取った整数 N を
int()
関数を使って整数型に変換します。 'L'
と'ng'
の文字列を連結し、その間に'o'
を N 個連結しています。- 得られた文字列を
print()
関数を使用して出力します。
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関数は、文字型で返してくれるため、文字のままの扱いでゼロの数を数えています。
n = int(input())
:ユーザーから整数 N を入力します。bin(n)
を使用して、整数 N を2進数表記に変換し、文字列としてbin_str
に格納します。reversed(bin_str)
を使用して、2進数表記を逆順にしたリストreversed_bin_str
を作成します。これにより、末尾から数えることができます。ans
を初期化して、末尾の0の個数をカウントする変数を用意します。- リスト
reversed_bin_str
を反復処理し、末尾から0の個数をカウントします。1を見つけたらループを終了します。 - 最終的な末尾の0の個数を
ans
から取得し、それを出力します。
C問題:Even Digits
問題
非負整数 n が次の条件を満たすとき、n を 良い整数 と呼びます。
- n を 10 進法で表したときに、偶数の数字 (0,2,4,6,8) のみが登場する。
例えば 0、68 および 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番目の数字であり、この番号を考慮しています。
下記がコードの詳細です。
decimal_to_quinary
関数:decimal_number
を5進数に変換します。- 0が入力された場合、5進数も0となります。
- 10進数を5で割り、余りを文字列の前に追加していきます。
make_good_num
関数:- 5進数を”良い整数”に変換します。
trans_num
辞書を使って、各5進数の桁を対応する偶数に変換します。- コメントアウトされた部分は、別の方法で同じ操作を行う例です。
- メイン処理:
- 入力から整数Nを入力して受け取ります。
n-1
をdecimal_to_quinary
に渡して5進数に変換し、その結果をmake_good_num
に渡して”良い整数”に変換します。- 最後に、求めた”良い整数”を出力します。
感想
今回は、B問題までしか解けなかったので、少し悔しいですね。
このコンテストでは、N進数や文字列を扱う問題が目立ちました。
A問題は、特定の文字の繰り返しを扱う問題で、比較的簡単でした。ただ、文字列の組み合わせを ‘+’ 記号で表現する部分には、少し戸惑いました(笑)。
B問題では、2進数への変換と文字列処理を駆使して、数字を逆順に数える問題に挑戦しました。最初は戸惑いましたが、ネットで2進数の変換方法を調べ、すぐに解決策を見つけました。ただ、bin()関数の使い方をすぐに忘れてしまうのが課題です。
C問題は、偶数のみを使って特定の数字を作る問題でした。数字の組み合わせについては考えが及んだのですが、具体的な実装方法が思いつかず、時間切れになってしまいました。5進数を利用するアプローチは斬新で、他の問題にも応用できそうだと感じました。
結果としてはB問題までの解答で、Ratingが15ポイント下がり、541になりましたが、とても勉強になるコンテストだったと思います。これからも楽しみながら、競技プログラミングに挑戦し続けたいと思います。
それでは、皆さんも競プロライフを楽しんでくださいね!(*^▽^)/
コメント