Filling up a hand with random cards that are not yet drawn - Monte Carlo
In the end, I opt to replace Mersenne Twister with another PRNG, xoroshiro128+, it managed to cut the compute time by around 15%. I also did some minor optimization on the for-loop but the improvement is minuscule. Anyway, here is the same function but with new PRNG:

Seeding in HandEvaluator's constructor:

HandEvaluator::HandEvaluator()
{
    Initialize();
    MTGenerator.seed(std::chrono::high_resolution_clock::now().time_since_epoch().count());

    s[0] = std::chrono::high_resolution_clock::now().time_since_epoch().count();
    std::cout &lt;&lt; "Seed 1: " &lt;&lt; s[0] &lt;&lt; "\n";

    s[1] = std::chrono::high_resolution_clock::now().time_since_epoch().count();
    std::cout &lt;&lt; "Seed 2: " &lt;&lt; s[1] &lt;&lt; "\n";
}


HandEvaluator's RandomFill function:

void HandEvaluator::RandomFill(std::vector&lt;std::shared_ptr&lt;Card&gt;&gt;&amp; _Set, std::vector&lt;std::shared_ptr&lt;Card&gt;&gt;&amp; _Dead, unsigned int _Target)
{
    //Add the cards that are currently in Set as dead cards
    for (auto const&amp; CardInSet : _Set)
    {
        if (CardInSet == nullptr)
            break;

        _Dead.push_back(CardInSet);
    }

    bool IsDead;
    unsigned int RequiredAmt = _Target - _Set.size();

    for (unsigned int Index = 0; Index &lt; RequiredAmt; Index++)
    {
        while (true)
        {
            _Set.push_back(ReferenceDeck[next() % 52]);

            IsDead = false;

            for (auto const&amp; Dead : _Dead)
            {
                if (Dead-&gt;IsEqualTo(_Set[_Set.size() - 1]))
                {
                    IsDead = true;
                    break;
                }
            }

            if (IsDead)
                _Set.pop_back();
            else
                break;
        }
    }
}