# Arup Guha
# 11/8/2023
# DP Code to calculate theoretical probability of a match with a fixed
# number X when we have k people choose a random number from [1, n].

# This function will return a list where p[i] will equal the probability
# that k randomly independently randomly chosen values from [1..n] will
# encompass precisely i unique values.
def distribution(n, k):

    dp = []
    for i in range(k+1):
        dp.append([])
        for j in range(k+1):
            dp[i].append(0)

    dp[0][0] = 1
    dp[1][1] = 1

    # i is # of random values generated.
    for i in range(2, k+1):

        # j is number of unique values.
        for j in range(1, i+1):

            # Take probability of j unique values out of i-1, times prob
            # last value is one of the old j values.
            dp[i][j] += dp[i-1][j]*j/n

            # Take probability of j-1 unique values of of i-1, times prob
            # last value is one of the new values (n - (j-1) = n - j + 1.
            dp[i][j] += dp[i-1][j-1]*(n-j+1)/n;

    return dp[k]

# Theoretically determine the probability that k randomly selected values from
# [1..n] matches one randomly chosen value from [1..n]
def solve(n, k):

    # This is the distribution of having i unique values when k are selected
    # from [1..n]
    p = distribution(n, k)

    res = 0

    # Add up probability over all cases (1 unique value, 2 unique values, etc.)
    for i in range(1, k+1):

        # If i unique values are chosen, then the probability one of them
        # matches a fixed one is i/n. This occurs in p[i] of the cases.
        res += (i/n)*p[i]

    return res


print(solve(365, 100))
