[Python] ABC008 C

問題

C – コイン

解説を読めば理解はできるけど、自分は思いつけるようになるのだろうか?

順列 99点回答

コインの順列に対して全探索を行います。

Pythonでは、itertools.permutations(iterable, r=None) を使うことで、順列を簡単に求めることができます。

例えば、[2, 4, 8] というコインの順列は、以下のように取り出すことができます。

>>> import itertools
>>> lst_coin = [2, 4, 8]
>>> list(itertools.permutations(lst_coin))
[(2, 4, 8), (2, 8, 4), (4, 2, 8), (4, 8, 2), (8, 2, 4), (8, 4, 2)]

コードは下記のようになります。

import itertools

N = int(input())
lst_coin = [int(input()) for _ in range(N)]

permutations_coin = list(itertools.permutations(lst_coin))

ans = 0
count = 0
for perm_coin in permutations_coin:
    # heads:=1 tail:=0
    lst_heads_tail = [1 for _ in range(N)]
    for i in range(N):
        for j in range(i+1, N):
            if perm_coin[j] % perm_coin[i] == 0:
                if lst_heads_tail[j] == 1:
                    lst_heads_tail[j] = 0
                else:
                    lst_heads_tail[j] = 1
    ans += sum(lst_heads_tail)
    count += 1

print(ans/count)

期待値 100点回答

それぞれの順列ごとに最終的に表になる枚数を数える、そして足し合わせる、という発想から転換します。

あるコイン\(C\)が最終的に表を向くためには、その左側に\(C\)の約数となるコインが偶数枚置かれている必要があります。

つまり、あるコイン\(C\)とその約数の順列を考えた時、あるコイン\(C\)が奇数番目に置かれる順列が、該当する順列になります。

\(C\) の約数が書かれたコインの枚数を\(S\)とします。

\(S\) 枚のコインの順列は \(S!\) 通りありますが、それぞれの確率は等しいので個別に考える必要はなく、 あるコイン\(C\)が奇数番目に置くことができるのは何通りあるかだけを考えます。

このようなコイン \(C\) の置き方は、\(S\) が奇数であれば\(\frac{S+1}{2}\)通り、 \(S\) が偶数であれば\(\frac{S}{2} + 1\)通り存在します。

また、コイン \(C\) の置き方は全体では \(S+ 1\)通り存在するので、それぞれの確率は、 \(S\) が奇数であれば\(\frac {\frac{S+1}{2}}{ S+ 1 }=\frac{1}{2}\)、 \(S\) が偶数であれば\(\frac{\frac{S}{2} + 1} { S+ 1 }=\frac{S+2}{2S+2} \) となります。

この確率を各コインについて足し合わせることで、答えが求まります。

import itertools

N = int(input())
lst_coin = [int(input()) for _ in range(N)]

p_ans = 0

for i in range(N):
    # あるコインCの約数となるコインを求める。
    lst_divisor = []
    for j in range(N):
        if i != j and lst_coin[i]%lst_coin[j]==0:
            lst_divisor.append(lst_coin[j])
    # 約数となるコインの枚数を求める。
    s = len(lst_divisor)
    # あるコインCが奇数番目に置かれる確率を求める。
    if s%2 == 1:
        p = 1/2
    else:
        p = (s+2) / (2*s + 2)
    
    p_ans += p

print(p_ans)