結果

問題 No.173 カードゲーム(Medium)
ユーザー qwewe
提出日時 2025-05-14 13:08:08
言語 C++17
(gcc 13.3.0 + boost 1.87.0)
結果
TLE  
実行時間 -
コード長 9,080 bytes
コンパイル時間 1,204 ms
コンパイル使用メモリ 112,944 KB
実行使用メモリ 7,840 KB
最終ジャッジ日時 2025-05-14 13:09:36
合計ジャッジ時間 6,263 ms
ジャッジサーバーID
(参考情報)
judge4 / judge2
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
other AC * 2 TLE * 1 -- * 7
権限があれば一括ダウンロードができます

ソースコード

diff #

#include <iostream>
#include <vector>
#include <numeric>
#include <map> // Use map for memoization and storing distributions
#include <vector>
#include <algorithm>
#include <iomanip>
#include <utility> // For pair

using namespace std;

int N; // Number of cards per player / number of matches
double PA, PB; // Probabilities for A and B to play their smallest card
vector<int> A_cards_initial, B_cards_initial; // Initial hands for A and B

// Memoization table: maps state (mask_A, mask_B) to the probability distribution of final score differences
// The distribution map maps score difference (int) to probability (double)
map<pair<int, int>, map<int, double>> memo;

// Helper function to get the list of currently available cards for a player based on their mask
// Returns a vector of pairs: {card_value, original_index}
// The original index is needed to update the bitmask correctly
vector<pair<int, int>> get_cards(int mask, const vector<int>& initial_cards) {
    vector<pair<int, int>> current_cards;
    // Efficiently count bits to reserve space, might offer minor speedup
    current_cards.reserve(__builtin_popcount(mask)); 
    for (int i = 0; i < N; ++i) {
        // If the i-th bit is set in the mask, the i-th card from the initial hand is available
        if ((mask >> i) & 1) {
            current_cards.push_back({initial_cards[i], i});
        }
    }
    return current_cards;
}

// Recursive function with memoization to calculate the probability distribution of final score differences
// state is defined by the masks representing remaining cards for A and B
map<int, double> solve(int mask_A, int mask_B) {
    // Base case: No cards left. The game ends. Score difference from this point is 0 with probability 1.0.
    if (mask_A == 0) { 
        return {{0, 1.0}};
    }
    
    // Define the current state using the masks
    pair<int, int> state = {mask_A, mask_B};
    
    // Check if the result for this state is already computed and stored in the memo table
    auto it = memo.find(state);
    if (it != memo.end()) {
        return it->second; // Return cached result
    }

    // Get the current hands for A and B based on the masks
    vector<pair<int, int>> current_A_cards = get_cards(mask_A, A_cards_initial);
    vector<pair<int, int>> current_B_cards = get_cards(mask_B, B_cards_initial);
    
    // k is the number of cards remaining for each player
    int k = current_A_cards.size(); 
    
    // Initialize the resulting distribution for the current state
    map<int, double> res_dist; 

    // Case 1: Only one card left for each player (k=1)
    // They must play these cards. Probability of this move is 1.0.
    if (k == 1) {
        int val_A = current_A_cards[0].first; // A's card value
        int idx_A = current_A_cards[0].second; // A's card original index
        int val_B = current_B_cards[0].first; // B's card value
        int idx_B = current_B_cards[0].second; // B's card original index

        // Calculate the score difference change for this match
        int score_diff_change = 0;
        if (val_A > val_B) { // A wins the match
            score_diff_change = val_A + val_B; 
        } else { // B wins the match (cards are distinct, so val_B > val_A)
            score_diff_change = -(val_A + val_B); 
        }
        
        // The next state has masks with the played cards removed (becomes empty masks)
        // Recursively call `solve` for the next state. This will hit the base case.
        map<int, double> sub_dist = solve(mask_A ^ (1 << idx_A), mask_B ^ (1 << idx_B)); 
        
        // Update the result distribution for the current state
        // For each possible final score difference D_sub from the subproblem,
        // the final score difference from the current state is (score_diff_change + D_sub).
        // The probability p_sub is carried over.
        for (auto const& [D_sub, p_sub] : sub_dist) {
             res_dist[score_diff_change + D_sub] += p_sub; 
        }

    } else { // Case 2: Two or more cards left for each player (k >= 2)
        // Find the minimum card value and its original index for player A
        int min_A_val = 1001, min_A_idx = -1; // Initialize min_A_val > max possible card value
        for(const auto& p : current_A_cards) {
            if (p.first < min_A_val) {
                min_A_val = p.first;
                min_A_idx = p.second;
            }
        }

        // Find the minimum card value and its original index for player B
        int min_B_val = 1001, min_B_idx = -1; // Initialize min_B_val > max possible card value
         for(const auto& p : current_B_cards) {
            if (p.first < min_B_val) {
                min_B_val = p.first;
                min_B_idx = p.second;
            }
        }

        // Iterate over all possible pairs of cards that A and B can play
        for (const auto& pA : current_A_cards) {
            int val_A = pA.first;
            int idx_A = pA.second;
            double prob_A; // Probability that A plays this card `val_A`

            // Calculate probability based on A's strategy
            if (idx_A == min_A_idx) { // A plays the smallest card
                prob_A = PA;
            } else { // A plays a card other than the smallest
                 // k >= 2 is guaranteed in this branch
                 prob_A = (1.0 - PA) / (k - 1);
            }

            for (const auto& pB : current_B_cards) {
                int val_B = pB.first;
                int idx_B = pB.second;
                double prob_B; // Probability that B plays this card `val_B`

                // Calculate probability based on B's strategy
                 if (idx_B == min_B_idx) { // B plays the smallest card
                    prob_B = PB;
                } else { // B plays a card other than the smallest
                     // k >= 2 is guaranteed in this branch
                     prob_B = (1.0 - PB) / (k - 1);
                }

                // Probability of this specific pair (A plays val_A, B plays val_B) occurring
                double prob_pair = prob_A * prob_B; 
                
                // Optimization: If probability is negligible, skip computation for this pair
                // Using a small epsilon threshold
                if (prob_pair < 1e-18) continue; 

                // Calculate the score difference change for this match
                int score_diff_change = 0;
                if (val_A > val_B) { // A wins the match
                    score_diff_change = val_A + val_B; 
                } else { // B wins the match
                    score_diff_change = -(val_A + val_B); 
                }

                // Determine the masks for the next state by removing the played cards
                // Use XOR to toggle the corresponding bit off
                int next_mask_A = mask_A ^ (1 << idx_A);
                int next_mask_B = mask_B ^ (1 << idx_B);
                
                // Recursively call `solve` for the next state
                map<int, double> sub_dist = solve(next_mask_A, next_mask_B);

                // Update the result distribution for the current state
                // Aggregate probabilities from the subproblem outcomes
                for (auto const& [D_sub, p_sub] : sub_dist) {
                    // The final score difference `score_diff_change + D_sub` occurs with probability `prob_pair * p_sub`
                    res_dist[score_diff_change + D_sub] += prob_pair * p_sub;
                }
            }
        }
    }

    // Store the computed distribution in the memo table before returning
    return memo[state] = res_dist;
}


int main() {
    // Use faster I/O operations
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);

    // Read input values: N, PA, PB
    cin >> N >> PA >> PB;
    
    // Resize vectors to hold N cards each
    A_cards_initial.resize(N);
    B_cards_initial.resize(N);

    // Read initial cards for player A
    for (int i = 0; i < N; ++i) cin >> A_cards_initial[i];
    // Read initial cards for player B
    for (int i = 0; i < N; ++i) cin >> B_cards_initial[i];
    
    // The initial state has all cards available for both players
    // The mask `(1 << N) - 1` has the lower N bits set to 1.
    int initial_mask = (1 << N) - 1;
    
    // Call the recursive function starting from the initial state
    // This computes the probability distribution of the final score difference
    map<int, double> final_dist = solve(initial_mask, initial_mask);

    // Calculate the total probability that player A wins
    // A wins if the final score difference (A's score - B's score) is strictly positive (D > 0)
    double prob_A_wins = 0.0;
    for (auto const& [D, p] : final_dist) { // Iterate through the final distribution map
        if (D > 0) { // Check if score difference is positive
            prob_A_wins += p; // Add the probability of this outcome to the total
        }
    }

    // Print the final result with high precision
    cout << fixed << setprecision(17) << prob_A_wins << endl;

    return 0;
}
0