結果
問題 |
No.173 カードゲーム(Medium)
|
ユーザー |
![]() |
提出日時 | 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 |
ソースコード
#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; }