🔙
🔝

【paiza問題集 解説】
Cランクレベルアップメニュー

標準入出力

標準入出力

STEP: 1 単純な入出力

単純な入出力

    S = input()
    print(S)
    

    問題集をこなしてきた方ならもうここでつまづくことはないでしょう。うっかりミスにだけ注意!ちゃんと動作確認をしてから提出してくださいね。

STEP: 5 半角スペース区切りでの出力

半角スペース区切りでの出力

    n = int(input())
    s = ['paiza' for _ in range(n)]
    print(*s)
    

    Python3 は半角スペース区切りの出力がめんどくさいので、一旦リスト化してから print(*) で展開するとよいでしょう。

FINAL問題 標準入出力

標準入出力

  • 例1

  • N = int(input())
    for _ in range(N):
        s, a = input().split()
        print(s, int(a) + 1)
    
  • 例2

  • N = int(input())
    lst = [input().split() for _ in range(N)]
    for s, a in lst:
        print(s, int(a) + 1)
    
  • 例3

  • N = int(input())
    dic = {s: int(a) for _ in range(N) for s, a in [input().split()]}
    for s, a in dic.items():
        print(s, a+1)
    

    データを作るか作らないか、またどんな型でデータを作るかで書き方が大きく変わってきます。「一覧表を出力してください。」としか記述されてませんので、どのように入力するかは自由かと思います。

    ということで、例1~3が理解できれば FINAL問題 は合格でしょう。ぺーぺーの私が偉そうなこと言えませんけど。😹

文字列

文字列

STEP: 1 整数と文字列

整数と文字列

    n = int(input())
    a = [input() for _ in range(n)]
    for s in a:
        print(len(s))
    

    文字列の長さを取得するにはlen()関数を使います。

STEP: 2 部分文字列

部分文字列

    a = input()
    s = input()
    if a in s:
        print('YES')
    else:
        print('NO')
    

    文字(列)a が、文字列s の一部分 (部分文字列)」として含まれているかを in で調べます。

STEP: 3 数字の文字列操作(基本)

数字の文字列操作(基本)

  • 例1

  • S = input()
    a = int(S[0]) + int(S[3])
    b = int(S[1]) + int(S[2])
    print(str(a) + str(b))
    
  • 例2

  • S = list(map(int, input()))
    a = S[0] + S[3]
    b = S[1] + S[2]
    print(str(a) + str(b))
    

    int()str()を駆使します。

STEP: 4 数字の文字列操作(0埋め)

数字の文字列操作(0埋め)

  • 例1

  • n = input()
    print(n.zfill(3))
    
  • 例2

  • n = input()
    print(f"{n:0>3}")
    

    0 埋めに便利な文字列型の.zfill()というメソッドがあります。引数に桁数(文字数)を与えると、勝手に 0 埋めしてくれます。これを知らないと試行錯誤してしまいます。

    例2のf文字列を使うとこんな見た目になります。0 は 0埋め、> は右寄せ、3 は3桁という意味です。(この順で書く必要があります)

STEP: 5 数字の文字列操作(時刻1)

数字の文字列操作(時刻1)

    S = input()
    print(*S.split(':'), sep='\n')
    

    .split()メソッドの引数に : を与えると : の位置で分割されたリストが返ります。

    S = 12:34 の時
    ['12', '34']

STEP: 6 数字の文字列操作(時刻2)

数字の文字列操作(時刻2)

  • 例1

  • S = input()
    hour, minute = map(int, S.split(':'))
    d, m = divmod(minute+30, 60)
    print(str(hour + d).zfill(2) + ':' + str(m).zfill(2))
    
  • 例2

  • S = input()
    hour, minute = map(int, S.split(':'))
    d, m = divmod(minute+30, 60)
    print(f"{hour+d:0>2}:{m:0>2}")
    

    divmod(minute+30, 60) は、(minute+30) // 60(minute+30) % 60 を計算してくれます。結果が (div, mod) の形で返るので、これを d, m にアンパック代入します。

    d は 分 + 60 の繰り上がり分、m はそのまま 分 となります。

    .zfill()メソッドで 0 埋めできますが、どうしても冗長になってしまいます。そんな時は f文字列が便利です。

FINAL問題 文字列

文字列

    N = int(input())
    
    for _ in range(N):
        t, tmp = input().split(maxsplit=1)
        th, tm = map(int, t.split(':'))
        h, m = map(int, tmp.split())
        
        time_h, time_m = divmod(tm + m, 60)
        time_h = (th + h + time_h) % 24
        
        print(f'{time_h:0>2}:{time_m:0>2}')
    

    入力した文字列を分割していくのが大変です。まずは時刻と時間に分割します。次に時刻を : で分割します。次に時間を分割します。

    tm は時刻の「分」、m は外出している時間の「分」。これを足して 60 で割ります。

    そして時刻の「時」の部分と外出時間の「時」の部分と (tm + m) // 60time_h を足すと帰宅時刻の「時」の部分が出るので、これを 24 で割って 24時間制にします。(26時なら 26 % 24 で 2時に)

    あとはこの結果を使って画面に出力するだけです。もちろん.zfill()メソッドを使った書き方でもOKです。

forループ

forループ

STEP: 1 3の倍数のカウント

3の倍数のカウント

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

    「3の倍数」とは、3で割り切れる数のことです。それをリストの中から見つけてカウントしていきます。

STEP: 2 フラグ管理

フラグ管理

  • 例1

  • n = int(input())
    
    flg = False
    for _ in range(n):
        a = int(input())
        
        if a == 7:
            flg = True
            break
    
    if flg:
        print('YES')
    else:
        print('NO')
    
  • 例2

  • n = int(input())
    
    for _ in range(n):
        a = int(input())
        
        if a == 7:
            print('YES')
            break
    else:
        print('NO')
    

    例1は、フラグ(flag)を立てる方法です。初めはフラグを False に下した状態にして、ある条件を満たすとフラグを立てる、True にし、そしてそのフラグの状態がのちの条件分岐の判定に使われます。
    昔からゲームでよく使われる手法として知られているので、「フラグが立った」とか「死亡フラグ」とかの意味で使われるフラグは、このプログラミング用語から来ているものと思われます。(後にゲーム用語ともなります)

    Python3 的にはelse を使えばフラグは必要なくなります。

    else については「3章 補足」で学習できます。

STEP: 3 インデックス取得

インデックス取得

    n = int(input())
    a = [int(input()) for _ in range(n)]
    k = int(input())
    
    idx = a.index(k) + 1
    print(idx)
    

    入力にひとクセある問題です。a_i の中で k を見つけるのですが、k の入力が a の後にあります。その為、a はデータとして初めに全取得しておく必要があります。

    それ以外は特筆することもありません。

STEP: 4 多重ループ

多重ループ

  • 例1

  • m = int(input())
    c = [input() for _ in range(m)]
    n = int(input())
    S = [input() for _ in range(n)]
    
    for s in S:
        for c_i in c:
            if c_i in s:
                print('YES')
            else:
                print('NO')
    
  • 例2

  • m = int(input())
    c = [input() for _ in range(m)]
    n = int(input())
    S = [input() for _ in range(n)]
    
    for s in S:
        for c_i in c:
            print('YES' if c_i in s else 'NO')
    

    cS のどっちが先かでちょっと混乱するところですが、「 S のワード中に c_i の文字は含まれるか」の順番です。

    どっちが先かで混乱しただけならまだ良いのですが、二重ループの処理がまだうまくイメージ出来ていない場合は、もう一度二重ループを復習しておいたほうが良いと思います。
    二重ループについてはちょっとだけ「1章 繰り返し文」で学習できます。

FINAL問題 forループ

forループ

  • 例1

  • N, _, K = map(int, input().split())
    
    for i in range(N):
        a = list(map(int, input().split()))
        cnt = 0
        for a_i in a:
            if a_i == K:
                cnt += 1
    
        print(cnt)
    
  • 例2

  • N, _, K = map(int, input().split())
    
    for i in range(N):
        a = list(map(int, input().split()))
        print(a.count(K))
    
  • 例3

  • N, _, K = map(int, input().split())
    a = [list(map(int, input().split())) for _ in range(N)]
    
    for lst in a:
        print(lst.count(K))
    

    ここで求められている書き方は恐らく例1です。例1が余裕で読めるようになっているならば、今後は素直に.count()メソッドを使いましょう。

ソート

ソート

STEP: 1 昇順ソート

昇順ソート

  • 例1

  • n = int(input())
    a = [int(input()) for _ in range(n)]
    sorted_a = sorted(a)
    print(*sorted_a, sep='\n')
    
  • 例2

  • n = int(input())
    a = [int(input()) for _ in range(n)]
    a.sort()
    print(*a, sep='\n')
    
  • 例3

  • n = int(input())
    a = [int(input()) for _ in range(n)]
    
    for i in range(n-1):
        for j in range(n-i-1):
            if a[j] > a[j+1]:
                a[j], a[j+1] = a[j+1], a[j]
    
    print(*a, sep='\n')
    

    例1は関数を使った昇順ソート。例2はメソッドを使った昇順ソートです。

    一見難しそうなソートですが、実は今まで学んだテクニックだけでソートが出来ます。それが例3のバブルソートという方法です。

    • 配列
    • スワップ (値交換)
    • 二重ループ

    これらのワードが何かはもうおわかりですよね?
    バブルソートは現在の値(a[j])と右隣りの値(a[j+1])を比べて、現在の値(a[j])のほうが大きかったらスワップする。というのを二重ループを使って処理していきます。

    a = [2, 4, 3, 5, 1] の時

    2 4 3 5 1

    2 4 3 5 1

    2 4 3 5 1

    4 と 3 をスワップ

    2 3 4 5 1

    2 3 4 5 1

    5 と 1 をスワップ

    2 3 4 1 5

    2 3 4 1 5

    2 3 4 1 5

    2 3 4 1 5

    4 と 1 をスワップ

    2 3 1 4 5

    2 3 1 4 5

    2 3 1 4 5

    3 と 1 をスワップ

    2 1 3 4 5

    2 1 3 4 5

    2 と 1 をスワップ

    1 2 3 4 5

    完成!

STEP: 2 降順ソート

降順ソート

  • 例1

  • n = int(input())
    a = [int(input()) for _ in range(n)]
    sorted_a = sorted(a, reverse=True)
    print(*sorted_a, sep='\n')
    
  • 例2

  • n = int(input())
    a = [int(input()) for _ in range(n)]
    a.sort(reverse=True)
    print(*a, sep='\n')
    
  • 例3

  • n = int(input())
    a = [int(input()) for _ in range(n)]
    
    for i in range(n-1):
        for j in range(n-i-1):
            if a[j] < a[j+1]:
                a[j], a[j+1] = a[j+1], a[j]
    
    print(*a, sep='\n')
    

    降順ソートでは関数やメソッドの引数に reverse=True を付けます。(例1・例2)

    例3では、文の比較式の、不等号の向きを反対にしただけです。それ以外は一切手を付けていません。

STEP: 3 辞書式ソート

辞書式ソート

    n = int(input())
    lst = [list(map(int, input().split())) for _ in range(n)]
    lst.sort(reverse=True)
    for a, b in lst:
        print(a, b)
    

    バナナのソートをどのようにすればよいかが悩ましいところですが、実は sorted().sort() が、問題の条件通りに勝手に並び替えてくれます。

    数が多いほうが上位になるので、降順ソートに指定するだけです。

FINAL問題 ソート

ソート

    N = int(input())
    lst = [list(map(int, input().split()))[::-1] for _ in range(N)]
    
    lst.sort(reverse=True)
    for s, g in lst:
        print(g, s)
    

    1つ前の「辞書式ソート」と同じ様に見えて、入力の前後が反転されています。この反転された値を反転すれば同じ様に書けます。

    最後は反転したものをもう一度反転して戻した形で画面に出力すれば完了です。

辞書

辞書

STEP: 1 辞書の基本

辞書の基本

  • 例1

  • n = int(input())
    dic = {}
    for _ in range(n):
        s, a = input().split()
        dic[s] = int(a)
    
    S = input()
    print(dic[S])
    
  • 例2

  • n = int(input())
    dic = {s: int(a) for _ in range(n) for s, a in [input().split()]}
    S = input()
    
    print(dic[S])
    

    入力のほうが難しいですね。😅
    ちなみに、a は文字列のままでも正解になります。「財産」ということなので数値化したまでです。

STEP: 2 辞書のデータ更新

辞書のデータ更新

    n = int(input())
    players = {input(): 0 for _ in range(n)}
    
    m = int(input())
    for _ in range(m):
        p, a = input().split()
        players[p] += int(a)
    
    S = input()
    print(players[S])
    

    辞書は、入力と同時に 0 で初期化しておきます。あとは名前とダメージを受け取りながら辞書に値を足していくだけです。

    最後に入力で受け取った S の値を画面に出力すれば完了です。

    できたら全回復するところまで作ってほしかったですね。このままじゃかわいそうだ。😅

STEP: 3 辞書データの順序

辞書データの順序

    n = int(input())
    players = {input(): 0 for _ in range(n)}
    m = int(input())
    
    for _ in range(m):
        p, a = input().split()
        players[p] += int(a)
    
    for _, v in sorted(players.items()):
        print(v)
    

    1つ前の「辞書データ更新」の最後の出力が異なるだけです。
    .items()メソッドは辞書をリストに変換する機能です。

    辞書型のメソッドは「2章 辞書を使いこなす機能一覧」で学習できます。

FINAL問題 辞書

辞書

  • 例1

  • p, q, _ = map(int, input().split())
    A = {i: j for _ in range(p) for i, j in [input().split()]}
    B = {j: k for _ in range(q) for j, k in [input().split()]}
    
    A_to_C = {}
    for i, j in A.items():
        A_to_C[i] = B[j]
    
    for i, k in sorted(A_to_C.items()):
        print(i, k)
    
  • 例2

  • p, q, _ = map(int, input().split())
    A = {i: j for _ in range(p) for i, j in [input().split()]}
    B = {j: k for _ in range(q) for j, k in [input().split()]}
    
    A_to_C = {i: B[j] for i, j in A.items()}
    
    for i, k in sorted(A_to_C.items()):
        print(i, k)
    

    頼んだ仕事を勝手に別の人に丸投げされて、そのままその仕事が行方不明になるということはたまにあるものです。再委託は違法にすべし!

    グループA と グループC を繋ぐ グループB の使い方が鍵となります。
    まず A.items()ij を取り出します。この i は グループA の i 番目の人、j は グループB の j 番目の人です。
    そして B[j] の値が グループC の k 番目の人で、この値を A_to_C[i] の値として辞書に格納します。この A_to_C[i]i は、最初に仕事を任せた グループA の i 番目の人です。

    A_to_C[i] … グループA の i 番目の人
    B[j] … グループC の k 番目の人

    ループを抜けると A_to_C のデータが出来上がっているので、これをソートして順に画面に出力すれば完了となります。内包表記のほうがわかりやすいような気がします。

    入力 r は何に使えばよいのだろう?と考えた蛇使いの方もいらっしゃるかと思います。この r は Python3 では使いません。気にしないでください。

    それと、プログラム例では番号を文字列で処理しましたが、整数型にしても正解になります。『番号』だから文字列でいいと思います。

シミュレーション

シミュレーション

STEP: 1 条件を満たす最小の自然数

条件を満たす最小の自然数

  • 例1

  • print(10013 - 10000 % 13)
    
  • 例2

  • n = 10000
    while n % 13 != 0:
        n += 1
    
    print(n)
    

    例1の解答はお呼びでなかったようで。😅

    例2は、10000 から 1 ずつ足しながら 13 で割り切れる数を探しているだけです。ループする回数が定まっていないので を使います。

STEP: 2 シミュレーションの練習

シミュレーションの練習

    n = int(input())
    a, b = map(int, input().split())
    paiza = kyoko = 1
    
    cnt = 0
    while kyoko <= n:
        kyoko += paiza * a
        paiza += kyoko % b
        cnt += 1
    
    print(cnt)
    

    paiza = kyoko = 1 という書き方をすると、全ての変数が最も右の値でまとめて代入されます。最も右の値は変数でも構いません。

    「霧島京子の数がnより大きくなるまで繰り返します。」とあります。 を使い、n より大きくなると終了(kyoko > n で False)なので、ループの条件を「 n 以下 kyoko <= n」にします。

    あとは各演算を間違えなければ問題は起こらないはずです。

FINAL問題 シミュレーション

シミュレーション

    H = int(input())
    paiza_hp = H
    
    n = 2
    paiza_damaged = [1, 1]
    monster_damaged = [1, 1]
    paiza_hp -= sum(monster_damaged)
    while paiza_hp > 0:
        paiza_hits = paiza_damaged[n-1] + paiza_damaged[n-2]
        monster_damaged.append(paiza_hits)
        
        monster_hits = monster_damaged[n-1]*2 + monster_damaged[n-2]
        paiza_damaged.append(monster_hits)
        paiza_hp -= monster_hits
    
        n += 1
    
    print(n)
    

    フィボナッチ数のようなダメージ計算式ですね。

    初期設定は1回目と2回目はどちらもダメージ 1 と決まっているので、上記のとおりに初期化しました。sum()関数を使わなくて直接 2 にしてもOK。
    そしてダメージ計算は3ターン目から開始します。

    今回は自分で変数名を考えなければならない個数が多くて大変です。私のセンスの無さが露呈しています。😓
    まずはループ条件を「パイザ君の HP が 0 より大きい」にします。文の中身はパイザ君の攻撃ダメージとモンスターの攻撃ダメージを問題文の通りに計算し、それぞれのリストに追加します。この時、ループの条件となっているパイザ君の HP もここで引いておきます。

    ループを抜けたら、最後にターン数の n を画面に出力して完了です。

    この問題が1回でクリアできなかったとしても、解説を読んで修正してクリアできればCランクのスキルチェックがそれなりに解けるようになっています。基礎を身に付けて慣れることはもちろんですが、カギは便利な関数やメソッドをたくさん憶えることです。これが手っ取り早い。あとは問題をよく読んで理解すること。問題集と違ってスキルチェックの問題は理解しやすいです。けど早まると勘違いもしやすいです。

    スキルチェックは制限時間がありますのでついつい時間を気にして焦ってしまいますが、初めのうちはタイムオーバーも気にせずじっくりと問題を解いていってみてください。力がつけば自然と早く解けるようになってきます。それと同時にBランクレベルの問題集をこなしていくと、Cランクのスキルチェックがだんだんと簡単に解けるようになってきます。

    スキルチェックの問題は難易度の低い順に上から並んでいますので、題名に惹かれたものからやってみてください。