Editorial for Card Counting


Remember to use this editorial only when stuck, and not to copy-paste code from it. Please be respectful to the problem author and editorialist.
Submitting an official solution before solving the problem yourself is a bannable offence.

Author: tango

There are too many cards to simply try every set of five cards and see which ones form a full house. So we will need to use some maths to calculate the answer.

Firstly, count how many cards there are of each rank. Suppose there are C_i cards of rank i for each i\in\{\text{A},2,3,4,5,6,7,8,9,10,\text{J},\text{Q},\text{K}\}.

Then, given two ranks i\ne j, the number of full houses with 3 cards of rank i and 2 cards of rank j is \binom{C_i}3\binom{C_j}2=\frac1{12}C_iC_j(C_i-1)(C_i-2)(C_j-1). Sum over all 182 possible pairs of ranks to get the total number of full houses (which fits in a long long).

Finally, the number of hands of five cards is exactly \binom N5=\frac1{120}N(N-1)(N-2)(N-3)(N-4), which also fits in a long long. Divide one number by the other to get the desired probability.

Taking in the input is O(n) time complexity. While we have to check all possible pairs of cards, we are using a frequency counter to do so, and there is a limited amount (13^2) possible pairs so the overall time complexity is still O(n). The solution uses O(1) space as the map representing the card deck can only have up to 13 entries in it.

C++ solution:

#include <bits/stdc++.h>
using namespace std;

int main() {
    int n;
    cin >> n;

    unordered_map<string, int> freqs;
    string x;
    for (int i = 0; i < n; i++) {
        cin >> x;
        freqs[x]++;
    }

    long long numerator = 0;

    for (auto [card1, freq1]: freqs) {
        for (auto [card2, freq2]: freqs) {
            if (card1 == card2 || freq1 < 2 || freq2 < 3) continue;
            numerator += 1ll * freq1*(freq1-1)/2 * freq2*(freq2-1)*(freq2-2)/6;
        }
    }

    long long denominator = 1ll * n*(n-1)*(n-2)*(n-3)*(n-4)/120;
    cout << (double)numerator/denominator << endl;
}

Python solution:

from collections import Counter
from math import comb

n = int(input())

cards = input().split()
freqs = Counter(cards)

fullhouses = 0
for k1, v1 in freqs.items():
    for k2, v2 in freqs.items():
        if k1 == k2 or v1 < 2 or v2 < 3:
            continue
        fullhouses += comb(v1, 2) * comb(v2, 3)

print(fullhouses / comb(n, 5))

Comments

There are no comments at the moment.