こんにちは、こんぶちゃ(茶コーダー)です!
初心者視点から競プロAtCoderのABC297のA問題〜C問題の自身の解答と解答説明をしていきます。
まだまだ学習の身ですので、最適コードではない部分も多々あるかと思いますが、その部分は同じ学習者として温かい気持ちで応援&ご助言頂けば嬉しいです。
では早速行ってみましょう!
今回の参加コンテスト(ABC297)
A問題:Double Click
問題(要約)
ダブルクリックが成立(x2 – x1 ≦ D, x1, x2は時刻)したかを確認する
解答
# 番号1
n,d=map(int,input().split())
T=list(map(int,input().split()))
# 番号2
for i in range(1,n):
if T[i] - T[i-1] <= d:
exit(print(T[i]))
# 番号3
print(-1)
考え方 (下の番号は、コード内のコメント番号と連携している)
- それぞれの入力を受け取る
- 空白区切りで与えられるn, dをinput()で受け取り、split()で分割しリスト化する。
map関数を用いて2つの整数に整数型を当てはめ、1つ目をn、2つ目をdとする - 空白区切りで与えられる配列Tも上記同様に受け取り、配列で保持するためlist()で配列とする
- 空白区切りで与えられるn, dをinput()で受け取り、split()で分割しリスト化する。
- クリックした時間が保持されている配列Tを順番に調べ、x2 – x1 ≦ d が成立しているかを確認する
- for文を用いて配列を一つづつ取り出す。ただし、取り出し要素とその一つ前の要素を比較するため、0始まりでなく、1始まりにしている
- if文を用いて指示文の数式(x2 – x1 ≦ D)が成立するかどうかを確認する
ここでは、 x2: T[i], x1: T[i-1] としている- 上記条件が成り立った場合、T[i] (x2) を出力する。
- この場合は、プログラムをこれ以上実行する必要がないため、exit関数を用いてプログラムを終了させている
- if文を用いて指示文の数式(x2 – x1 ≦ D)が成立するかどうかを確認する
- for文を用いて配列を一つづつ取り出す。ただし、取り出し要素とその一つ前の要素を比較するため、0始まりでなく、1始まりにしている
- 指示の条件が満たされていない場合のみ、最後のprint文が実行される。そのため、print文で -1 を出力する
B問題:chess960
問題(要約)
長さ8の文字列において、下記条件が満たしているかを判断する
- 文字列内に2つ存在する “B” の左からの位置が偶奇異なる
- “K” は 2つの “R” の間にある
解答
# 番号1
S=input()
# 番号2
# 番号3
B,K,R=[],[],[]
# 番号4
for i in range(len(S)):
if S[i]=="B":
B.append(i)
elif S[i]=="K":
K.append(i)
elif S[i]=="R":
R.append(i)
# 番号5
if B[0]%2 == B[1]%2:
exit(print("No"))
if R[0]<K[0]<R[1]:
print("Yes")
else:
print("No")
考え方(下の番号は、コード内のコメント番号と連携している)
- 文字列入力を受け取り、受け取ったものをSとする(文字列のまま扱う)
- B, K, Rの文字列が何番目にあるかを確認し、提示された条件に当てはまるかを確認する
- B, K, Rが何番目にあるかを格納するための空配列を作成する
*カンマ区切りで1行で記載することが可能(B=[ ], K=[ ], R=[ ]を3行で記載と同じ) - for文を用いて、文字列を一つづつ調べる。
*len関数を用いることにより文字列の長さを求め、その回数繰り返す- 文字列Sの i番目が “B” と等しい場合
- 配列Bに番号 i を格納する
- 文字列Sの i番目が “K” と等しい場合
- 配列Kに番号 i を格納する
- 文字列Sの i番目が “R” と等しい場合
- 配列Rに番号 i を格納する
- 文字列Sの i番目が “B” と等しい場合
- 上記for文にて取得したそれぞれの番号が提示された条件に当てはまるかを確認する
- 文字列Bは2つ存在し、それぞれの偶奇が異なる必要がある
- 上記より配列Bは2つの数字が入っている
- 偶奇判定は、2で割った余りが等しいか異なっているかで判断する
- B[0] % 2 == B[1] %2 が等しい時は偶奇が等しい
* “%”であまりを求めることができる- 条件に当てはまらないため、printで”No”を出力しながら、exitでプログラムを終了させる
- B[0] % 2 == B[1] %2 が等しい時は偶奇が等しい
- 文字列”K”が、文字列”R”の間にあるかを確認する
- if文を用いてR[0] < K[0] < R[1] が成り立つかを確認する
- 条件が成り立つ場合は、”Yes”をprint文で出力する
- 条件が成り立たない場合は、”No”をprint文で出力する
- if文を用いてR[0] < K[0] < R[1] が成り立つかを確認する
- 文字列Bは2つ存在し、それぞれの偶奇が異なる必要がある
C問題:PC on the Table
問題(要約)
H個の長さWの、”. “(ドット)、”T”から成る文字列S1, S2, ・・・, SH の与えられる。文字列”TT”の箇所を”PC”に置き換えることができ、置き換え後のS1, S2, ・・・, SHを出力する
解答
# 番号1
h,w=map(int,input().split())
# 番号2
S=[list(input()) for _ in range(h)]
# 番号3
for i in range(h):
for j in range(w-1):
if S[i][j]=="T" and S[i][j+1]=="T":
S[i][j],S[i][j+1]="P","C"
# 番号4
for i in range(h):
print(*S[i],sep="")
考え方(下の番号は、コード内のコメント番号と連携している)
- 入力h, wの受け取りを行う
- 空白区切りの入力をinput()で受け取り、split()で空白毎に分割する
- map関数を適用することにより、各要素に整数型(int)を適用する
- 0番目をh, 1番目をwとして入力を受けとる
- 複数行に渡って入力される文字列Sを内包表記を用いて、2次元配列で取り込む
- input()を用いて入力を受け取り、list()を用いて配列の形式に変換する
- 内包表記を用いて、上記の取り組みをh回繰り返す(for文)
*入力例1では、S=[[‘T’, ‘T’, ‘T’], [‘T’, ‘.’, ‘T’]] のような形式になる
- 2重for文を用いて、各列各行に”TT”が含まれていないかを調べ、条件が当てはまる場合は”PC”に置き換える
- 列方向をスキャンするためのfor文をカウンタ i を用いて定義する
- 行方向をスキャンするためのfor文をカウンタ j を用いて定義する。
- 行方向は、連続する値( “TT” )が入っているかを確認するため、w-1までとする
- if文を用いて、連続する “TT” があるかどうかを確認する
- つまり、S[i][j] == “T” とS[i][j+1] == “T” が共に成り立つどうかを判断する
- 条件が当てはまる場合は、S[i][j] = “P”, S[i][j+1] = “C” を代入する
*配列Sを直接書き換えに行く
- 条件が当てはまる場合は、S[i][j] = “P”, S[i][j+1] = “C” を代入する
- 列方向をスキャンするためのfor文をカウンタ i を用いて定義する
- 書き換えた配列Sを求める回答の形で出力する
- for文を用いて列数分繰り返す
- リストのアンパック(*:アスタリスク)を用いてprint文を使い行単位で出力を行う
*アンパック:リスト内要素を一覧で出力可能。ただし、要素間にスペース区切りが入る - 求める回答には要素間のスペースが不要なため、print文のオプションの”sep”を用いて、スペース間を詰める
- リストのアンパック(*:アスタリスク)を用いてprint文を使い行単位で出力を行う
- for文を用いて列数分繰り返す
感想
C問題まで比較的レベルが高くない問題でした。いつもよりも素早く解けましたが、順位は上がらず・・・。簡単な場合はスピードも重視しつつ、解いていく必要がありますね。
それでは、良い競プロライフを〜!
コメント