🔙
🔝

【paiza問題集 解説】
paizaの森練習問題コンテスト過去問題セット16

3つの数

3つの数

    print(8)
    print(1)
    print(3)
    

    数なので文字列にならないよう注意。といっても、文字列に強制変換されてから画面に出力されるので、文字列でも正解になりますけど。😅

    この数以外にしたら内申書に悪い事書かれそう!😂

税込価格

税込価格

  • 例1

  • p = int(input())
    s = input()
    
    if s == 'T':
        tax_in = int(p * 1.1)
    else:
        tax_in = int(p * 1.08)
    
    print(tax_in)
    
  • 例2

  • p = int(input())
    s = input()
    
    if s == 'T':
        tax_in = p + p*10//100
    else:
        tax_in = p + p*8//100
    
    print(tax_in)
    
  • 例3

  • p = int(input())
    s = input()
    tax_rate = {'T' : 10, 'E': 8}
    
    tax_in = p + p * tax_rate[s] // 100
    
    print(tax_in)
    

    例1は小数を扱った例、例2は小数を回避して計算した例、例3は 文を使わずに辞書で税率を判定しているものです。

パターン検出

パターン検出

    N = int(input())
    S = [input() for _ in range(N)]
    T = input()
    
    for s in S:
        if s in T:
            print('Yes')
            break
    else:
        print('No')
    

    一度全ての入力を取得しないと組めないタイプです。それさえ済めば、あとはお馴染みのパターンです。😉


    よければ 以降を、

    print('Yes' if 〜 else 'No')
    

    と、一文で書いて動くようにしてみてくださいな。

連続ホームラン

連続ホームラン

    n, m = map(int, input().split())
    print((1 / n) ** m)
    

    『ホームランは確率で打つものじゃない!!』と集中砲火を浴びそうな問題ですね。🤣

    「物事が連続で起きる確率」は、1回の確率を回数分掛けると求められます。
    例えば10分の1の確率の事象が3回連続で起きる確率は、

    110×110×110=11000

    (110)3=11000=0.001

    となります。(赤字がプログラム部分)

辞書順で 3 番目に小さい文字列

辞書順で 3 番目に小さい文字列

    _ = input()
    s = input()
    
    sorted_s = sorted(s)
    sorted_s[-2], sorted_s[-3] = sorted_s[-3], sorted_s[-2]
    
    print(''.join(sorted_s))
    

    小狡い方法ですが、『辞書順で 3 番目に小さい文字列』は、昇順ソート後の文字列の末尾から数えて2番目の文字と3番目の文字を入れ替えた文字列になります。

    paiza 解答コード例では組み合わせを作ってくれるモジュールをインポートし、permutations() 関数を使って組み合わせを作っています。

    print(*sorted(itertools.permutations(s)), sep='\n')
    
    ('a', 'b', 'c')
    ('a', 'c', 'b')
    ('b', 'a', 'c')
    ('b', 'c', 'a')
    ('c', 'a', 'b')
    ('c', 'b', 'a')

    これの3番目を取っています。ただしこの方法、もんんんんんんんんのすごく重いです。😅
    1文字増えるごとに相乗的にクソ重くなります。組み合わせを1つずつ作って排出するジェネレータ式ではなく、全組み合わせをこの場で一気に作ってしまうからです。
    初めは私も好んで使っていましたが、この方法では組み合わせ数によってはタイムアウトしてしまいます。やってらんないので、それからは一切使わなくなりました。😅

    この問題でも10文字の長さにすると若干時間がかかってしまいます。試しに解答コード例を使って11文字以上に、例えば s = 'abcdefghijk' などにしてその場で実行してみてください。1文字増えるだけで相当重くなるのが体感でわかります。(本提出までしなくて大丈夫)

村人の友好関係(easy)

村人の友好関係(easy)

    N, M, Q = map(int, input().split())
    nodes = {n: {i: 0 for i in range(1, N+1) if i!=n} for n in range(1, N+1)}
    
    for _ in range(M):
        a, b, f = map(int, input().split())
        nodes[a][b] = f
        nodes[b][a] = f
    
    group = set()
    for _ in range(Q):
        op, q = input().split()
        
        if op == '+':
            group.add(int(q))
        else:
            group.remove(int(q))
    
    result = 0
    if 0 < len(group) < N:
        result = max(max(v for k, v in nodes[g].items() if k not in group) for g in group)
    
    print(result)
    

    重み付き無向グラフ&クエリ問題ですね。重み付きグラフはまだ学習済ませてない。😖


    nodes = {n: {i: 0 for i in range(1, N+1) if i!=n} for n in range(1, N+1)}
    

    村人 n 以外の村人との友好度を 0 に初期化して作っています。

    {村人 n: {n 以外の村人 i: 友好度}}

    というデータ構造になっています。


    for _ in range(M):
        a, b, f = map(int, input().split())
        nodes[a][b] = f
        nodes[b][a] = f
    

    ここで無向グラフを作り、重み(友好度)を付けています。村人 a と 村人 b の友好度は f ということです。その逆向きも作ります。




    group = set()
    for _ in range(Q):
        op, q = input().split()
        
        if op == '+':
            group.add(int(q))
        else:
            group.remove(int(q))
    

    グループの入退会を行うクエリです。イベントは '+' '-' の2つのみで、それに合わせて入退会のクエリ処理を行なっています。条件に、不整合となる値は与えられないことが保証されていますので、退会処理はわかりやすい .remove() メソッドを使いました。このメソッドは引数の値がセットに含まれていない時にはエラーとなりますので注意が必要です。

    この処理が完了すると、最終的にグループに残っている村人の番号が記録されています。



    result = 0
    if 0 < len(group) < N:
        result = max(max(v for k, v in nodes[g].items() if k not in group) for g in group)
    
    print(result)
    

    グループに残っている各村人の持つ、他の村人との友好度を取り出して最大値を求めます。これが内側の max() 関数です。
    そしてグループに残っている各村人の持つ友好度の最大値リストから最大値を求めます。ややこしいな。😅
    それが外側の max() 関数です。これで easy なのか・・・。


    問題の複雑さや条件が多くて混乱激しいですが、これくらいならまだどうとでも解けるから easy なんでしょうね。😓

  • paiza 解答コード例

  • n, m, q = map(int, input().split())
    
    # 隣接行列の作成
    ga = [[0 for j in range(n)] for i in range(n)]
    for i in range(m):
        a, b, f = map(int, input().split())
        a -= 1
        b -= 1
        ga[a][b] = ga[b][a] = -f
    
    
    # ログに基づいて更新する
    is_member = [False for i in range(n)]
    for i in range(q):
        line = input().split()
        op = line[0]
        v = int(line[1]) - 1
        if op == '+':
            is_member[v] = True
        else:
            is_member[v] = False
    
    max_f = 0
    for a in range(n):
        for b in range(n):
            f = ga[a][b]
            if is_member[a] and not is_member[b] or not is_member[a] and is_member[b]:
                max_f = max(-f, max_f)
    print(max_f)
    

    隣接行列を使った解き方をされています。コメント「隣接行列の作成」の所で二次元リストで行列を作っています。なぜここで f を負数に変えているのか、その理由は私にはちょっとわかりません。😅


    # ログに基づいて更新する
    is_member = [False for i in range(n)]
    for i in range(q):
        line = input().split()
        op = line[0]
        v = int(line[1]) - 1
        if op == '+':
            is_member[v] = True
        else:
            is_member[v] = False
    

    プログラム例ではグループのデータを「加入中」の村人のみをセット型で管理していましたが、解答コード例では (村人の番号 - 1) を要素番号と紐付けて bool型 で管理しています。加入中は True、そうでない場合は False です。


    max_f = 0
    for a in range(n):
        for b in range(n):
            f = ga[a][b]
            if is_member[a] and not is_member[b] or not is_member[a] and is_member[b]:
                max_f = max(-f, max_f)
    print(max_f)
    

    隣接リストの初めから終わりまで全ての値(友好度)を調べていきます。a は行列の行、b は列にあたります。

    村人 a と 村人 b がグループに所属する者同士かどうか、この条件式では同士でない場合に True としています。そして記録している max_f の最大値の比較更新を行います。

    2
        3 2 2
        1 2 1
        1 3 3
        + 1
        + 2
    

    ①   0 1 3
    │\  1 0 0
    ②─3 3 0 0
    グループ同士扱いとして False

       0 1 3
    \  1 0 0
    ─3 3 0 0
    グループ同士なので False

       0 1 3
      1 0 0
    ②─ 3 0 0
    max_f = 3

       0 1 3
    \  1 0 0
    ─3 3 0 0
    グループ同士なので False

    ①   0 1 3
    │\  1 0 0
    ─3 3 0 0
    グループ同士扱いとして False

    ①   0 1 3
    │\  1 0 0
    ②→3 3 0 0

    ①   0 1 3
      1 0 0
    ②─3 3 0 0
    3は非グループなので False

    ①   0 1 3
    │\  1 0 0
    ←3 3 0 0
    3は非グループなので False

    ①   0 1 3
    │\  1 0 0
    ②─ 3 0 0
    3は非グループなので False

    3

    村人が他の全ての村人と必ず関係していますので、こうしてみると隣接行列のほうがわかりやすいですね。😅
    でもグループ管理はセットのほうが扱いやすいので、混ぜ合わせるとより良いものができそうですが、それはぜひともご自身で作ってみてください。


    この問題、グループ内の村人間むらびとかんの友好度が最も大きい時のテストケースが存在しないようですので、これを考慮しない誤ったプログラムでも100点が取れてしまいますね。😅
    この不具合はまずい…。プログラムの組み方で回避しましょう。