🔙
🔝

【paiza問題集 解説】
ループメニュー2

偶奇の判定

偶奇の判定

STEP: 1 未知数個の数の受け取り

未知数個の数の受け取り

    a = list(map(int, input().split()))
    
    i = 0
    while True:
        print(a[i])
        if a[i] == -1:
            break
        i += 1  # ← これを忘れずに!
    

    ループする回数が定まっていません。そんな時はの出番となります。
    は条件式が True の時にループします。今回は「-1 が入力されるまで」ということなので「無条件」に True としておきます。

    まず数値を画面に出力します。これは -1 であった場合にも画面に出力しなければならない為、優先して出力します。
    次にその数が -1 の時、ループを抜けてプログラムを終了します。それ以外の時は i に 1 を足してループを続けます。

    i += 1 を書かないと無限ループしますので注意してください。

STEP: 2 未知数個の文字列の受け取り

未知数個の文字列の受け取り

    s = input().split()
    
    i = 0
    while True:
        print(s[i])
        if s[i] == 'EOF':
            break
        i += 1
    

    1つ前の「未知数個の数の受け取り」の数が文字列になっただけで、ほとんど同じです。一応見比べてみて納得したら次の問題に移りましょう。😸

STEP: 3 奇数だけ出力

奇数だけ出力

    _ = input()
    a = list(map(int, input().split()))
    
    for i in a:
        if i % 2 == 1:
            print(i)
    

    奇数の判定は i % 2 == 1 で出来ます。憶えておきましょう。
    偶数の判定は i % 2 == 0 で出来ます。これも憶えておきましょう。

    日常では「余りの計算」を必要とすることはそうあるものではありませんが、プログラミングではかなり使います。特に「余りが 0 の時」という判定を使います。算数でも特に割り算が苦手という方は、割り算の商と余りを同時に計算してくれるdivmod()関数が便利ですので、これを使えるようになると理解の助けとなる上にラクでオススメです。👍

STEP: 4 割り切れる数だけ出力

割り切れる数だけ出力

    _ = input()
    a = list(map(int, input().split()))
    
    for i in a:
        if i % 3 == 0:
            print(i)
    

    割り切れる場合は == 0 となります。i を 3 で割り切れるかどうかの条件式の書き方は i % 3 == 0 となります。「 i3割った余り0 の時」です。

FINAL問題 偶奇の判定

偶奇の判定

  • 例1

  • _ = input()
    a = list(map(int, input().split()))
    
    for i in a:
        if i % 2 == 1:
            print('odd')
        else:
            print('even')
    
  • 例2

  • _ = input()
    a = list(map(int, input().split()))
    
    for i in a:
        if i % 2 == 0:
            print('even')
        else:
            print('odd')
    

    奇数(odd オッド)と偶数(even イーブン)の判定を、例1が「奇数の時」、例2が「偶数の時」で行なっています。どちらでも構いませんが、どっちにしようか迷った時は、多用する「 0 の時」(例2)にしておくとよいでしょう。

約数の列挙

約数の列挙

STEP: 1 各桁の和

各桁の和

    N = input()
    
    sum_ = 0
    for i in N:
        sum_ += int(i)
    
    print(sum_)
    

    早い話が一桁ずつ数を足していってその合計を求めなさいということです。
    12345 の時は 1 + 2 + 3 + 4 + 5 の合計をプログラムで書いて求めます。
    N文にかけて1つずつ足していくだけです。その際、N は文字列となっていますので、int()で数値に変換してから計算にかけます。

STEP: 2 カウント変数を使った計算

カウント変数を使った計算

  • 例1

  • N = int(input())
    M = list(map(int, input().split()))
    
    i = 1
    while i <= N:
        print(M[i-1] * i)
        i += 1
    
  • 例2

  • N = int(input())
    M = list(map(int, input().split()))
    
    for i in range(N):
        print(M[i] * (i+1))
    
  • 例3

  • _ = input()
    M = list(map(int, input().split()))
    
    for i, m in enumerate(M, start=1):
        print(m * i)
    

    M = [8, 1, 3, 3, 1, 8] の時

    M 8 1 3 3 1 8
    i 1 2 3 4 5 6
    M_i * i 8 2 9 12 5 48

    M の 1番目は 8 。8 ✕ 1 = 8
    M の 2番目は 1 。1 ✕ 2 = 2
    M の 3番目は 3 。3 ✕ 3 = 9
    M の 4番目は 3 。3 ✕ 4 = 12
    M の 5番目は 1 。1 ✕ 5 = 5
    M の 6番目は 8 。8 ✕ 6 = 48

    enumerate()関数を使うとプログラムがすっきりします。
    enumerate()関数の使い方は「2章 リスト型データを使いこなす機能一覧」で学習できます。

STEP: 3 2 で何回割れる?

2 で何回割れる?

    n = int(input())
    
    cnt = 0
    while n % 2 == 0:
        n //= 2
        cnt += 1
    
    print(cnt)
    

    ループする回数が定まっていませんので、文を使います。
    ループを終了する条件を 2 で割り切れなくなった時 に設定します。逆に言うと 2 で割れる間はループしますので、n2 で割り、cnt を 1 増やします。

    2 で割り切れなくなった所でループを抜け、cnt の値を画面に出力して完了です。

STEP: 4 任意の数で何回割れる?

任意の数で何回割れる?

    n, M = map(int, input().split())
    
    cnt = 0
    while n % M == 0:
        n //= M
        cnt += 1
    
    print(cnt)
    

    1つ前の問題「2 で何回割れる?」の 2 が任意の数 M になっただけです。

STEP: 5 10 進数から 2 進数に変換

10 進数から 2 進数に変換

    N = input()
    
    N_bin = ''
    d = int(N)
    while d > 0:
        d, m = divmod(d, 2)
        N_bin = str(m) + N_bin
    
    print(N_bin)
    

    突然、難易度が跳ね上がりました。10進数から 2進数への変換方法がわからないと詰んでしまう難問です。😅

    まず「2進数」の説明からします。わかる方は飛ばしてください。

    10進数は一桁の数字が 0 〜 9 で 10個あるので 10進数。
    2進数は一桁の数字が 0 〜 1 で 2個あるので 2進数。
    それぞれ最後の数に 1 を足すと 1 繰り上がり、10 となります。この時、10進数では「じゅう」、2進数では「いちぜろ」と読みます。

    10進数 2進数
    0 0
    1 1
    2 10
    3 11
    4 100
    5 101
    6 110
    7 111

    この10進数を2進数に手動で変換してくださいということになります。やり方を知らないとわかりませんよね。😅

    10進数の 4 を 2進数に変換してみます。初めに 4 を 2 で割ります。

    4 // 2 = 2 余り 0
    2 // 2 = 1 余り 0
    1 // 2 = 0 余り 1

    商が 0 になったら終了です。この時の余りが 2進数となります。
    余りを上から見ていくと、2進数の一桁目から現れています。これを横にすると 100 (いちぜろぜろ)となります。

    本題に入ります。

    N = input()
    
    N_bin = ''
    d = int(N)
    while d > 0:
        d, m = divmod(d, 2)
        N_bin = str(m) + N_bin
    
    print(N_bin)
    

    このプログラム例は 2進数の一桁目から順に計算しています。d が商、m が余りです。
    まず入力した文字列を整数型に変換して d に代入して初期化します。
    それから、d が 0 になったら計算終了なので、の条件式は d > 0 にします。d が 0 より大きい間( 0 にならない間)、ループし続けます。

    d, m = divmod(d, 2)divmod(d, 2)は、d2 で割った商(d // 2)余り(d % 2)をそれぞれ計算し、(商, 余り)となって返ります。
    商は d に、余りは m に、つまり

    d =
    m = 余り

    とそれぞれ代入されます。
    ※ この代入の仕方を「アンパック代入」といいますが、今は憶えなくて構いません。

    この余りの mN_bin に格納します。一桁目から計算しているので、str(m) + N_bin の順番で繋げます。

    これを商が 0 になるまで繰り返し、商が 0 になったらループを抜け、最後に N_bin を画面に出力して完了となります。

    余談ですが、2進数は手でも数えられます。右手のひらを自分に向け、各指を立てた時を 1、折り曲げた時を 0 とすると、親指から順に片手で10進数の 31 まで数えることができます。2進数の数え方を学ぶのに丁度いいので練習してみてください。

    ただこの数え方、人前でやる時は注意してください。4 がヤバい。😅

STEP: 6 10 進数から M 進数に変換

10 進数から M 進数に変換

    N, M = map(int, input().split())
    
    N_bin = ''
    d = int(N)
    while d > 0:
        d, m = divmod(d, M)
        N_bin = str(m) + N_bin
    
    print(N_bin)
    

    1つ前の「10 進数から 2 進数に変換」の 2進数が M 進数になったものです。
    変換方法は全く同じで、2 を M に変えるだけです。以上!

STEP: 7 N が M ずつ増えたときにいつ K を越える?

N が M ずつ増えたときにいつ K を越える?

  • 例1

  • n, M, K = map(int, input().split())
    
    cnt = 0
    while n <= K:
        n += M
        cnt += 1
    
    print(cnt)
    
  • 例2

  • N, M, K = map(int, input().split())
    
    cnt = 0
    for n in range(N, K+1, M):
        cnt += 1
    
    print(cnt)
    

    N = 1 または n = 1
    M = 3
    K = 8 の時の cnt

    cnt  n 1 2 3 4 5 6 7 8 9 10
    0 1 2 3
    1 2 3

    上の表はループ実行時の cnt の値なのですが、 ではカウントのしかたが異なります。
    は M 増えてからカウントし、K を超えた時にループを抜けます。純粋に問題のとおりのプログラムになっています。
    は単純に range()に指定した引数に応じたループの回数分だけカウントしています。
    問題文のとおりに捉えると のほうがわかりやすいと思われますが、「K を超えるまでのループの回数」と捉えると のほうがわかりやすくなると思われます。

    どちらが正しいということはありませんので、その場の流れやお好きなほうでどうぞ。🐱

STEP: 8 毎日増加するお金

毎日増加するお金

    a, B = map(int, input().split())
    
    cnt = 0
    while a <= B:
        a = int(a * 1.1)
        cnt += 1
    
    print(cnt)
    

    1つ前の問題「N が M ずつ増えたときにいつ K を越える?」と考え方は同じです。その為、プログラムもほぼ同じ書き方になっています。

    注意点は、問題文にある「増加するお金は小数点以下切り捨てで考えることとします。」とありますので、a = int(a * 1.1) で計算後ごとに小数点以下を切り捨てて整数化しなければいけないところです。

    10% ずつ増えるということは、お金が 100% → 110% になるということです。110% = 1.1 なので、1.1 で掛け算しています。
    110% という書き方はできません。% は割り算した余りを計算する算術演算子ですので「110 ÷ ・・・何?」と解釈されて文法エラーになります。

STEP: 9 階乗の計算

階乗の計算

    N = int(input())
    
    n = N
    for i in range(N-1, 1, -1):
        n *= i
    
    print(n)
    

    階乗がわからないという場合、まずは「階乗 (Wikipedia)」を読んでください。と言っても、2行読めばもうわかります。😂

    まず変数 n に、入力した N を初期値として代入しておきます。
    次に N-1 から 2 までを 1 ずつ減らしながら順にループしていきます。1 で掛け算する意味はありませんので、2 まで( i が 1 になったらストップして直ちにループを抜ける)としています。こうして ni を掛け算していくと階乗が求められます。

    N = 5 の時

    54=20
    203=60
    602=120
    1201=120 ← 意味ない
  • range({スタートの数,} ストップする数{, ステップする数})

    {} の部分は省略できる。
    スタートの数を省略すると 0 になる。
    ステップする数を省略すると 1 になる。
    ステップは「いくつ跳びにする(増分)」ということです。

STEP: 10 階乗の末尾に 0 はいくつ付く?

階乗の末尾に 0 はいくつ付く?

    N = int(input())
    
    n = N
    for i in range(N-1, 1, -1):
        n *= i
    
    n = str(n)
    i = len(n) - 1
    cnt = 0
    while n[i] == '0':
        cnt += 1
        i -= 1
    
    print(cnt)
    

    paiza の解答コード例では前触れ無くいきなり数学的処理を持ち出されてきましたが、この流れで急にそれは無いでしょ!とツッコまれた方も多いことでしょう。Python3 では使用できる数の範囲に制限はありませんが、制限がある言語では巨大な数になる階乗をマトモに計算して扱うことができません。なので必然的に素因数分解とかワケわかめ(死語)なことをして解いているわけです。

    しかしここは「ループメニュー」の趣旨に沿い、使用できる数の範囲に制限の無い Python3 の強みを活かした真っ当なやり方で解いてみましょう。🐍もなかなかやるもんです。それともヒトのほうかな?

    まず初めに N の階乗を求めます。1つ前の「階乗の計算」と全く同じコードです。

    次に、求めた階乗の計算結果 n の末尾の 0 の個数を数えます。
    n を文字列型に変換し、末尾から 0 の個数をカウント cnt += 1 していきます。0 でない数字が見つかったらそこでカウントを終了し、画面に cnt を出力して完了です。

    末尾の 0 の個数を数える方法としてもう1つ、「10 で何回割れるか」をカウントすることでも解けます。

    N = int(input())
    
    n = N
    for i in range(N-1, 1, -1):
        n *= i
    
    cnt = 0
    while n % 10 == 0:
        n //= 10
        cnt += 1
    
    print(cnt)
    

    この問題集の流れからみて、こちらのほうがよりよい解答でしょう。

STEP: 11 加算された数列の最大値

加算された数列の最大値

  • 例1

  • N = int(input())
    a = list(map(int, input().split()))
    
    max_ = -float('inf')
    for i in range(N):
        max_ = max(max_, a[i] + i+1)
    
    print(max_)
    
  • 例2

  • _ = input()
    a = list(map(int, input().split()))
    
    max_ = -float('inf')
    for i, n in enumerate(a, start=1):
        max_ = max(max_, n + i)
    
    print(max_)
    

    「i を足したとき」の i とは、i 番目の i です。1番目から数えるので数列の先頭の数から i(番目) ずつ足していきます。

    a = [8, 9, 3, 8, 3] の時

    i(番目) 1 2 3 4 5
    n 8 9 3 8 3
    n + i 9 11 6 12 8
    max_ 9 11 11 12 12

    enumerate()関数の使い方は「2章 リスト型データを使いこなす機能一覧」で学習できます。

STEP: 12 加算された数列の最小値

加算された数列の最小値

    N = int(input())
    a = list(map(int, input().split()))
    
    min_ = float('inf')
    for i in range(N):
        min_ = min(min_, a[i] + i+1)
    
    print(min_)
    
  • 例2

  • _ = input()
    a = list(map(int, input().split()))
    
    min_ = float('inf')
    for i, n in enumerate(a, start=1):
        min_ = min(min_, n + i)
    
    print(min_)
    

    i を足した時の i とは、i 番目の i です。1番目から数えるので数列の先頭の数から i(番目) ずつ足していきます。

    a = [8, 9, 3, 8, 3] の時

    i(番目) 1 2 3 4 5
    n 8 9 3 8 3
    n + i 9 11 6 12 8
    min_ 9 9 6 6 6

    enumerate()関数の使い方は「2章 リスト型データを使いこなす機能一覧」で学習できます。

STEP: 13 1 はどこにある?

1 はどこにある?

    _ = input()
    a = list(map(int, input().split()))
    
    for i, n in enumerate(a, start=1):
        if n == 1:
            print(i)
    

    数列の先頭から 1 を探していき、見つけたらそれが何番目の 1 かを画面に出力していく流れです。1番目から数えるので、start=1 にします。

    enumerate()関数の使い方は「2章 リスト型データを使いこなす機能一覧」で学習できます。

STEP: 14 約数の個数

約数の個数

  • 例1

  • N = int(input())
    
    cnt = 0
    for i in range(1, N+1):
        if N % i == 0:
            cnt += 1
    
    print(cnt)
    
  • 例2

  • N = int(input())
    
    cnt = 0
    for i in range(1, N//2 + 1):
        if N % i == 0:
            cnt += 1
    
    print(cnt + 1)
    
  • 例3

  • N = int(input())
    nums = [1 for i in range(1, N//2 + 1) if N % i == 0]
    
    print(len(nums) + 1)
    #print(sum(nums) + 1)
    #print(nums.count(1) + 1)
    

    「 N を割り切る整数」とは、N % i == 0True になる i のことです。1 〜 N の中に True になる i がいくつあるかを求めるプログラムを書きましょうというのがこの問題です。

    例1は、1 〜 N まで順に N % i を計算して求めています。言葉どおり順当なやり方です。

    例2は、1 〜 N // 2 までしかループさせていません。これでも正しい結果が求められます。

    N = 10 の時

    i 1 2 3 4 5 6 7 8 9 10
    N % i 0 0 1 2 0 4 3 2 1 0
    True?

    上の表を見ると、6 〜 9 は ✕ になっています。

    10÷5=2
    10÷6=1.66666....
    10÷7=1.42857142857....
    10÷8=1.25
    10÷9=1.11111....
    10÷10=1

    6 〜 9 には 10 を割り切る整数は存在しません。これが N = 1000 の時で、N // 2 = 500 であっても i が 501 〜 999 の間に 1000 を割り切る整数は存在しないのです。

    その代わりループが半分で止まりますので、N % N = 0 となる N の分を 1 加算します。print(cnt + 1)+ 1 は、この N の分です。

    例3は内包表記で書いてありますが、ただ内包表記で書いたわけではなく、if N % i == 0True の時に要素を 1 にして、要素数 = カウント回数としています。
    また、要素の値が全て 1 なので、これを合計しても求められます。さらに 1 の数を数えることでも求められますし、1 ではなく True にしても求められます。

FINAL問題 約数の列挙

約数の列挙

    N = int(input())
    
    for i in range(1, N//2 + 1):
        if N % i == 0:
            print(i)
    
    print(N)
    

    1つ前の問題「約数の個数」の個数を「約数」、つまり i を見つけ次第その場で画面に出力していくだけです。

    余力があったら他の書き方もしてみてください。いろいろな書き方をしてみることも学習する上で有効な手段です。