paizaの森練習問題コンテストは、「paizaの森 (Discord)」にて約2か月に1回のペースで開催されており、ユーザー同士が開催時刻にpaizaの森に集まり「よーいドン」で与えられた数問の練習問題をお好きなプログラミング言語で解答する早さを競います。
( 第5回練習問題コンテストは D級3問, C級3問)
それほど難しい問題は出題されないですし、誤答によるペナルティーもありませんので初心者でも気軽に参加出来ます。
また、コンテストから数日後には出題された問題が一般公開され、だれでも挑戦できるようになります。
本記事で使用しているメソッド・アルゴリズムについて
解答例で使っているメソッドやアルゴリズムについて、下記の記事で詳しく解説していますので参考にしてみて下さい。
- [Ruby] 標準入力によるデータ取得1
- [Ruby] 標準入力によるデータ取得2
- [Ruby] 標準入力によるデータ取得3
- [Ruby] 標準出力(データを任意に整形して出力する)
- [Ruby] 文字列の連結・繰り返し・インデックス指定・置き換え
- [Ruby] 文字列を操作するメソッド
- [Ruby]ハッシュ(連想配列)の基本操作
- [Ruby]配列の基本操作1
- [Ruby]繰り返し処理
- [Ruby]条件分岐
第5回 paizaの森練習問題コンテスト
1問目: 3 割打者 (paizaランク D 相当)
打席数 n と ヒットの回数 m が半角スペース区切りで与えられ、打率が 3 割以上なら "Yes" 、そうでないなら "No" を出力する問題です。
入出力例
10 3
が入力されたら、yes
を出力する。(10 / 3 = 3.333...)
INPUT1 = <<"EOS" 10 3 EOS OUTPUT1 = <<"EOS" Yes EOS
Ruby 解答例1-1
m / n.to_f
で割り算結果を小数で求め、0.3 以上なら"Yes"、そうでないなら"No" を出力します。
(整数同士の割り算は整数が返り、整数と小数の割り算は小数が返るので、n を小数型に変換してから割っています)
# 解答例1-1 n, m = gets.split.map(&:to_i) if m / n.to_f >= 0.3 puts "Yes" else puts "No" end
Ruby 解答例1-2
小数型同士の割り算結果は小数が返ります。
# 解答例1-2 n, m = gets.split.map(&:to_f) puts m / n >= 0.3 ? "Yes" : "No"
Python3 解答例1-1
python では整数同士の割り算で小数が返ります。(/ の場合)
# 解答例1-1 n, m = map(int, input().split()) if m / n >= 0.3: print("Yes") else: print("No")
Python3 解答例1-2
# 解答例1-2 n, m = map(int, input().split()) print("Yes" if m / n >= 0.3 else "No")
2問目: テレワーク可能か (paizaランク D 相当)
スペース区切りでデスク使用率の整数 a と天気の文字列 b が与えられ、デスクの使用率が 30(%) を超える場合、または天気が rainy (雨) の場合は"Yes"、そうでないなら "No" を出力する問題です。
なお、与えられる天気は rainy, sunny, cloudy
のいずれかです。
入出力例
60 sunny
が入力されたら、Yes
を出力する。(デスク使用率が 60% なので)
INPUT1 = <<"EOS" 60 sunny EOS OUTPUT1 = <<"EOS" Yes EOS
Ruby 解答例1-1
if文の条件を || (or) で連結して分岐します。
# 解答例1-1 a, b = gets.split a = a.to_i if a > 30 || b == "rainy" puts "Yes" else puts "No" end
Ruby 解答例1-2
# 解答例1-2 a, b = gets.split puts a.to_i > 30 || b == "rainy" ? "Yes" : "No"
Python3 解答例1-1
# 解答例1-1 a, b = input().split() a = int(a) if a > 30 or b == "rainy": print("Yes") else: print("No")
Python3 解答例1-2
# 解答例1-2 a, b = input().split() print("Yes" if int(a) > 30 or b == "rainy" else "No")
3問目: 文字列の反転 (paizaランク D 相当)
文字列 s が与えられ、s を逆順にした文字列を出力する問題です。
※ 第3回コンテストでも同じ問題が出題されていますので今回はさくっと解説します。
入出力例
paiza
が与えられたらaziap
を出力する。
INPUT1 = <<"EOS" paiza EOS OUTPUT1 = <<"EOS" aziap EOS
Ruby 解答例
reverseメソッドで逆順にします。
# 解答例 puts gets.chomp.reverse
Python3 解答例
スライスで逆順にします。
# 解答例 print(input()[::-1])
4問目: CD (paizaランク C 相当)
1行目で 曲の数 n が整数で与えられ、続く n 行で 半角スペース区切りで 曲の時間(分) m と 曲の時間(秒) s が与えられます。
CDの最大収録時間を74分とした場合、n 曲全てを 1 枚の CD に収録できる場合は "Yes" 、そうでなければ "No" を出力する問題です。
入出力例
15
1 7
5 22
5 23
5 4
4 30
3 58
3 55
4 17
3 30
5 0
3 53
3 38
5 25
4 14
7 16
が入力されたらYes
を出力する。(曲の時間を全部足すと 66分32秒)
INPUT1 = <<"EOS" 15 1 7 5 22 5 23 5 4 4 30 3 58 3 55 4 17 3 30 5 0 3 53 3 38 5 25 4 14 7 16 EOS OUTPUT1 = <<"EOS" Yes EOS
Ruby 解答例1-1
n 曲分の演奏時間を秒に換算して合計値を求め、74分=4440秒 以下かを判定しています。
# 解答例1-1 MAX_RECORDING_SEC = 60 * 74 # 4440 秒 n = gets.to_i total_sec = 0 n.times do m, s = gets.split.map(&:to_i) total_sec += 60 * m + s end if total_sec <= MAX_RECORDING_SEC puts "Yes" else puts "No" end
Ruby 解答例1-1
解答例1-1を短くまとめた書き方です。
# 解答例1-2 MAX_RECORDING_SEC = 60 * 74 # 4440 秒 _, *songs = $stdin.read.split("\n").map { |r| r.split.map(&:to_i) } total_sec = songs.map { |m, s| 60 * m + s }.sum puts total_sec <= MAX_RECORDING_SEC ? "Yes" : "No"
Ruby 解答例2
二次元配列を縦に集計する書き方です。(分の合計と秒の合計をそれぞれ計算している)
# 解答例2 MAX_RECORDING_SEC = 60 * 74 # 4440 秒 _, *songs = $stdin.read.split("\n").map { |r| r.split.map(&:to_i) } m, s = songs.transpose.map { |a| a.inject(:+) } total_sec = 60 * m + s puts total_sec <= MAX_RECORDING_SEC ? "Yes" : "No"
Python3 解答例1-1
# 解答例1-1 MAX_RECORDING_SEC = 60 * 74 # 4440 秒 n = int(input()) total_sec = 0 for _ in range(n): m, s = map(int, input().split()) total_sec += 60 * m + s print(total_sec) if total_sec <= MAX_RECORDING_SEC: print("Yes") else: print("No")
Python3 解答例1-2
# 解答例1-2 MAX_RECORDING_SEC = 60 * 74 # 4440 秒 _, *songs = [list(map(int, r.split())) for r in open(0).read().strip().split("\n")] total_sec = sum([60 * m + s for (m, s) in songs]) print("Yes" if total_sec <= MAX_RECORDING_SEC else "No")
Python3 解答例2
# 解答例2 MAX_RECORDING_SEC = 60 * 74 # 4440 秒 _, *songs = [list(map(int, r.split())) for r in open(0).read().strip().split("\n")] m, s = [sum(x[i] for x in songs) for i in range(len(songs[0]))] total_sec = 60 * m + s print("Yes") if total_sec <= MAX_RECORDING_SEC else print("No")
5問目: サイクルヒット (paizaランク C 相当)
野球での5打席分の結果が整数0~4で与えられ、整数が下記の対応になっているときに、サイクルヒットを達成していれば"Yes"、そうでなければ"No"を出力する問題です。
サイクルヒットは、シングルヒット、ツーベースヒット、スリーベースヒット、ホームラン全てを1回以上打つと成立します。
打席結果の対応
- 1: シングルヒット
- 2: ツーベースヒット
- 3: ツリーベースヒット
- 4: ホームラン
- 0: それ以外
入出力例
4
3
2
0
1
が入力されたらYes
を出力する。
(シングルヒット1本、ツーベースヒット1本、スリーベースヒット1本、ホームラン1本、それ以外1本)
INPUT1 = <<"EOS" 4 3 2 0 1 EOS OUTPUT1 = <<"EOS" Yes EOS
Ruby 解答例1-1
各安打のフラグを用意して、該当すればtrueにし、最後に全ての安打フラグがtrueかを判定します。
(0はサイクルヒットに関係ないので無視します。)
# 解答例1-1 n = 5 single_hit = false two_base_hit = false three_base_hit = false home_run = false n.times do m_i = gets.to_i if m_i == 1 single_hit = true elsif m_i == 2 two_base_hit = true elsif m_i == 3 three_base_hit = true elsif m_i == 4 home_run = true end end if single_hit && two_base_hit && three_base_hit && home_run puts "Yes" else puts "No" end
Ruby 解答例1-2
解答例1-1のフラグを配列にした書き方。
# 解答例1-2 m = $stdin.read.split.map(&:to_i) # 0: 単打, 1: 二塁打, 2: 三塁打, 3: 本塁打 ciclehit = Array.new(4, false) # ciclehit = [false] * 4 でも OK m.each { |res| ciclehit[res - 1] = true if res > 0 } puts ciclehit.all? ? "Yes" : "No"
Ruby 解答例2-1
ハッシュを使って安打を集計する書き方。
# 解答例2-1 m = $stdin.read.split results = Hash.new(0) m.each { |res| results[res] += 1 if res != "0" } puts results.length == 4 ? "Yes" : "No"
Ruby 解答例2-2
selectメソッド と tallyメソッドを使って安打を集計する書き方。
# 解答例2-2 results = $stdin.read.split.select { |x| x != "0" }.tally puts results.length == 4 ? "Yes" : "No"
Python3 解答例1-1
# 解答例1-1 n = 5 single_hit = False two_base_hit = False three_base_hit = False home_run = False for _ in range(n): m = int(input()) if m == 1: single_hit = True elif m == 2: two_base_hit = True elif m == 3: three_base_hit = True elif m == 4: home_run = True if single_hit and two_base_hit and three_base_hit and home_run: print("Yes") else: print("No")
Python3 解答例1-2
# 解答例1-2 m = list(map(int, open(0).read().strip().split())) # 0: 単打, 1: 二塁打, 2: 三塁打, 3: 本塁打 ciclehit = [False] * 4 for res in m: if res > 0: ciclehit[res - 1] = True print("Yes" if all(ciclehit) else "No")
Python3 解答例2
辞書型で安打を集計する書き方。
# 解答例2 m = open(0).read().strip().split() results = {} for res in m: if res != "0": results[res] = results.get(res, 0) + 1 print("Yes" if len(results) == 4 else "No")
Python3 解答例3
辞書型(辞書内包表記)で安打を集計する書き方。
# 解答例3 if len({res for res in open(0).read().strip().split() if res != "0"}) == 4: print("Yes") else: print("No")
6問目: 条件を満たす最小の整数 (paizaランク C 相当)
整数x, y, z が半角スペース区切りで与えられ、
x 以上かつ、y で割った余りが z である、最小の整数
を出力する問題です。
入出力例
11 7 2
が入力されたら16
を出力する。
11 ÷ 7 = 1 あまり 4
12 ÷ 7 = 1 あまり 5
13 ÷ 7 = 1 あまり 6
14 ÷ 7 = 2 あまり 0
15 ÷ 7 = 2 あまり 1
16 ÷ 7 = 2 あまり 2 ← 答え!
INPUT1 = <<"EOS" 11 7 2 EOS OUTPUT1 = <<"EOS" 16 EOS
Ruby 解答例1-1
while文で、x ÷ y の余りが z になるか?を調べながら、x を 1ずつ増加させ、余りが z ならループを抜けて、 x を出力します。
# 解答例1-1 x, y, z = gets.split.map(&:to_i) while x % y != z x += 1 end puts x
Ruby 解答例1-2
timesメソッドで、解答例1-1と同じ処理をしています。
# 解答例1-2 x, y, z = gets.split.map(&:to_i) (y - 1).times do break if x % y == z x += 1 end puts x
Ruby 解答例2
計算で直接答えを求めます。
# 解答例2 x, y, z = gets.split.map(&:to_i) puts x + (z - x % y) % y
Python3 解答例1-1
# 解答例1-1 x, y, z = map(int, input().split()) while x % y != z: x += 1 print(x)
Python3 解答例1-2
# 解答例1-2 x, y, z = map(int, input().split()) for _ in range(y-1): if x % y == z: break x += 1 print(x)
Python3 解答例2
# 解答例2 x, y, z = gets.split.map(&:to_i) puts x + (z - x % y) % y
今回のまとめ
第5回コンテストでは、小数点数の割り算、複数条件での条件分岐、項目別に集計する問題などを解きました。
Cランク問題あたりから問題文も長くなってきますので、よく読んでしっかり理解してから解き始めましょう!
コンテスト時間は(たしか・・・)40分なので、Dランク3問、Cランク3問全問解くのはなかなか大変かも(*'ω'*)