SOMPO HD プログラミングコンテスト2021(AtCoder Beginner Contest 192)をPythonで解く

投稿日:  更新日:2022/09/02

Android Python

B!
Daniel AgreloによるPixabay(https://pixabay.com/)からの画像

こんにちは, Shinoryoです.

今回はSOMPO HD プログラミングコンテスト2021(AtCoder Beginner Contest 192)を, Pythonで解いてみた結果を書き連ねていこうと思います.

A - Star

求めるのは, X100で割った余りを100から引いた値です.

# 出力
print(100 - (int(input()) % 100))

B - uNrEaDaBlE sTrInG

文字列Sから奇数番目を取り出した文字列と偶数番目を取り出した文字列を用意します.

文字列の中の文字が大文字か小文字かを判定するには, .islower()や.isupper()を使用します.

.islower()は, 以下の2つの条件がどちらも満たされる場合, Trueを返します. そうでなければFalseを返します.

  • 文字列中に大文字と小文字の区別のある文字が1文字以上存在する.
  • その大文字と小文字の区別のある文字の全てが小文字である.

.isupper()は, 以下の2つの条件がどちらも満たされる場合, Trueを返します. そうでなければFalseを返します.

  • 文字列中に大文字と小文字の区別のある文字が1文字以上存在する.
  • その大文字と小文字の区別のある文字の全てが大文字である.

偶数番目を取り出した文字列に関する判定には注意が必要です. 文字列Sが1文字の場合, 偶数番目を取り出した文字列としては, おそらく何もない空白の文字列が用意されるはずです. そうすると, .isupper()としてはFalseが返ってきてしまうので, 偶数番目を取り出した文字列が空白である可能性を考慮しなければなりません.

# 入力
S = input()
# Sの長さを格納
Slength = len(S)
# 奇数番目だけ、偶数番目だけを用意
Seven = ""
Sodd = ""
for i in range(0, Slength, 2):
Seven += S[i]
for i in range(1, Slength, 2):
Sodd += S[i]
# 判定
if Seven.islower() and (Sodd.isupper() or not(Sodd)):
print("Yes")
else:
print("No")

C - Kaprekar Number

意外にも, 問題文にあることをそのまま実行すれば通ります. 「各桁の数字を大きい順に並び替えて」「各桁の数字を小さい順に並び替えて」には, 整数型を文字列型にして, その各文字を整数型にしてソートすればよいです.

# 整数列Sintlist_funcを入力されて、10進法におけるSintlist_funcの値を出力する関数
def Nshinhou(Sintlist_func):
output = 0
for i in Sintlist_func:
output = output * 10 + i
return output
# 整数iを入力されてg_1(i)を出力する関数
def g_1(i):
i_descending = sorted([int(x) for x in str(i)], reverse=True)
return Nshinhou(i_descending)
# 整数iを入力されてg_2(i)を出力する関数
def g_2(i):
i_ascending = sorted([int(x) for x in str(i)])
return Nshinhou(i_ascending)
# 整数iを入力されてf(i)を出力する関数
def f(i):
return g_1(i) - g_2(i)
# 入力
N, K = [int(x) for x in input().split()]
# 操作
for _ in range(K):
N = f(N)
# 出力
print(N)

D - Base n

N進法におけるXの値を出力する関数を用意するのは, 「C - Kaprekar Number」と同じなのでそこまで難しくはないでしょう.

N進数のNが大きいほど2桁目以降の表す値が大きくなっていくので, Nを大きくすればするほどXの値は大きくなる(狭義単調増加)ということになります. よって, 二分探索(binary search)を用いることができます.

ここで用いる二分探索の概要

二分探索とは, ソート済みのリストに対する検索を行うにあたって有用なアルゴリズムです.

  • あるlowとあるhighの値を用意します.
  • lowhighの真ん中の値としてmid=(low+high)/2をとります.
  • mid進法におけるXの値を確認します.
    • mid進法におけるXの値がM以下である(つまり, 条件を満たす)ならば, low=midとします(次は, より大きい値を確認します).
    • mid進法におけるXの値がMより大きい(つまり, 条件を満たさない)ならば, high=midとします(次は, より小さい値を確認します).
  • lowhighの差が1になるまで上の作業を続けます.

このようにして得られたlowhighについて, low以下では条件を満たし, high以上では条件を満たさないということになるので, 求める値はlowd(ただし, dXに含まれる最も大きい数字)となります.

lowとhighの初期値

二分探索を行うにあたって, lowhighの初期値を検討する必要があります.

  • lowdを採用します. もし(d+1)以上の全てのNに対して, N進法におけるXの値がMより大きい(つまり, 条件を満たさない)場合はlow=dとなり, 出力される値はdd=0となります.
  • highM+1を採用します. 後述するように, Xが2桁以上の場合(つまり, X=10以上)に対して二分探索を適用します. すると, M進法におけるXの値は必ずM以上になります. よって, (M+1)進法におけるXの値は必ずMより大きくなります.

細かい場合の補足

  • そもそもがlow+1>=highの場合:(d+1)以上の全てのNに対して, N進法におけるXの値がMより大きくなります. 下のコード例では「while low + 1 < high」として, low+1>=highの場合には二分探索を行わずlow=dとなるようになっています.
  • Xが1文字の場合:二分探索は使えないので, 最初に場合分けしておく必要があります.
# 整数列Xintlist_funcと底N_funcを入力されて、N_func進法におけるXintlist_funcの値を出力する関数
def Nshinhou(Xintlist_func, N_func):
output = 0
for i in Xintlist_func:
output = output * N_func + i
return output
# 入力
Xintlist = [int(x) for x in input()]
M = int(input())
# Xに含まれる最も大きい数字dを求めておく
d = max(Xintlist)
# Xの文字数が1文字のとき、(d+1以上の)全ての位取り記数法の場合で同じ値が得られる
# 2文字以上の場合とは決定的に違うので、場合分けをしておく
if len(Xintlist) == 1:
if Xintlist[0] <= M:
print(1)
else:
print(0)
else:
# 位取り記数法の底が増えていくと、その位取り記数法におけるXの値も増えていく(狭義単調増加)
# よって、二分探索を用いる
# 二分探索の初期値を与える
# lowはd
low = d
# highはM+1
high = M + 1
# 二分探索を実施
# lowとhighの差が1になるまで続ける
while low + 1 < high:
# lowとhighの平均をとる(小数点以下切り捨て)
mid = (low + high) // 2
# mid進法におけるXintlistの値を取得
value = Nshinhou(Xintlist, mid)
# 条件を満たしていれば、lowはmid以上の値であることが分かる
if value <= M:
low = mid
# そうでなければ、highはmid以下の値であることが分かる
else:
high = mid
# 二分探索の結果得られたlowとhighが境界
# 出力するべきはlow - d
print(low - d)

E以降

E以降は私の能力不足故に省略いたします.

参考にしたサイト等

Search

About Me

自分の写真
理系大学生でした. Bloggerを利用して発信を行っています.

Labels

Blog Archives