結果

問題 No.248 ミラー君の宿題
ユーザー maspymaspy
提出日時 2020-05-13 23:17:43
言語 PyPy3
(7.3.15)
結果
AC  
実行時間 2,283 ms / 5,000 ms
コード長 2,135 bytes
コンパイル時間 1,441 ms
コンパイル使用メモリ 87,136 KB
実行使用メモリ 84,424 KB
最終ジャッジ日時 2023-10-12 17:10:03
合計ジャッジ時間 17,752 ms
ジャッジサーバーID
(参考情報)
judge12 / judge14
このコードへのチャレンジ
(要ログイン)

テストケース

テストケース表示
入力 結果 実行時間
実行使用メモリ
testcase_00 AC 249 ms
79,516 KB
testcase_01 AC 242 ms
79,704 KB
testcase_02 AC 257 ms
79,700 KB
testcase_03 AC 268 ms
79,516 KB
testcase_04 AC 398 ms
79,364 KB
testcase_05 AC 314 ms
80,648 KB
testcase_06 AC 439 ms
81,704 KB
testcase_07 AC 631 ms
80,288 KB
testcase_08 AC 232 ms
79,740 KB
testcase_09 AC 2,283 ms
82,664 KB
testcase_10 AC 1,507 ms
81,544 KB
testcase_11 AC 405 ms
79,244 KB
testcase_12 AC 739 ms
80,220 KB
testcase_13 AC 2,014 ms
83,108 KB
testcase_14 AC 1,738 ms
84,204 KB
testcase_15 AC 2,002 ms
84,424 KB
testcase_16 AC 2,097 ms
83,756 KB
testcase_17 AC 391 ms
79,480 KB
権限があれば一括ダウンロードができます

ソースコード

diff #

import sys

read = sys.stdin.buffer.read
readline = sys.stdin.buffer.readline
readlines = sys.stdin.buffer.readlines

def ord_2(n):
    e = 0
    while n % 2 == 0:
        e += 1
        n >>= 1
    return e

def argmax_distribution(A):
    U = max(A)
    n = len(A)
    dist = [0] * (1<<n)
    full = (1<<n) - 1
    dist[full] += 0.5 ** sum(A)
    for u in range(1, U+1):
        eq = [0.0] * (1<<n)
        low = [0.0] * (1<<n)
        eq[0] = 1.0
        low[0] = 1.0
        for i in range(n):
            t = 0.5 ** (A[i] - u + 1)
            p_eq = t if A[i] >= u else 0.0
            p_low = t if u <= A[i] + 1 else 1.0
            for s in range(1<<i):
                eq[s^(1<<i)] = eq[s] * p_eq
                low[s^(1<<i)] = low[s] * p_low
        for s in range(1, 1<<n):
            dist[s] += eq[s] * low[full^s]
    return dist

def solve(nums):
    N = len(nums)
    dp = [0.0] * (1<<N)
    A = [ord_2(p-1) for p in nums]
    def compute_dp(s):
        if s == 0:
            return 0.0
        I = [i for i in range(N) if s & (1<<i)]
        n = len(I)
        if n == 1:
            return 1.0
        p_loop = 0
        x = 1.0
        # gcd で遷移する場合
        gcd_prob = [1.0] * (1<<n)
        ind = [0] * (1<<n)
        for k in range(n):
            i = I[k]
            for j in range(1<<k):
                ind[j + (1<<k)] = ind[j] + (1<<i)
                gcd_prob[j + (1<<k)] = gcd_prob[j] / (nums[i])
                gcd_prob[j] -= gcd_prob[j + (1<<k)]
        p_loop += gcd_prob[-1]
        B = [A[i] for i in I]
        for j in range((1<<n) - 1):
            x += gcd_prob[j] * (dp[ind[j]] + dp[s^ind[j]])
        # 2^n乗根で遷移する場合
        p0 = gcd_prob[0]
        dist = argmax_distribution([A[i] for i in I])
        p_loop += p0 * dist[-1] 
        for j in range((1<<n) - 1):
            x += p0 * dist[j] * (dp[ind[j]] + dp[s^ind[j]])
        return x / (1 - p_loop)
    for s in range(1<<N):
        dp[s] = compute_dp(s)
    return dp[-1]

T = int(readline())
for _ in range(T):
    N = int(readline())
    nums = list(map(int, readline().split()))
    print(solve(nums))
0