結果
問題 |
No.174 カードゲーム(Hard)
|
ユーザー |
![]() |
提出日時 | 2025-05-14 13:06:32 |
言語 | C++17 (gcc 13.3.0 + boost 1.87.0) |
結果 |
TLE
|
実行時間 | - |
コード長 | 7,950 bytes |
コンパイル時間 | 1,100 ms |
コンパイル使用メモリ | 120,396 KB |
実行使用メモリ | 90,656 KB |
最終ジャッジ日時 | 2025-05-14 13:07:45 |
合計ジャッジ時間 | 4,523 ms |
ジャッジサーバーID (参考情報) |
judge4 / judge1 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
other | AC * 2 TLE * 1 -- * 9 |
ソースコード
#include <iostream> #include <vector> #include <numeric> #include <algorithm> #include <map> #include <unordered_map> // Use unordered_map for potentially better average performance than map #include <iomanip> #include <cmath> // For basic math functions if needed // Platform-specific optimizations for bit manipulation intrinsics // Check compiler and include intrinsics if available #if defined(__GNUC__) || defined(__clang__) // GCC or Clang: use built-in functions __builtin_ctz and __builtin_popcount #define custom_ctz(x) __builtin_ctz(x) #define custom_popcount(x) __builtin_popcount(x) #elif defined(_MSC_VER) // MSVC: use intrinsics _BitScanForward and __popcnt #include <intrin.h> // Define custom_ctz equivalent for MSVC inline unsigned long msvc_bsf_ulong(unsigned long mask) { unsigned long index; // _BitScanForward returns non-zero if a set bit is found and sets index. // Returns zero if mask is zero. if (_BitScanForward(&index, mask)) return index; // The behavior of __builtin_ctz(0) is undefined. // In this code, ctz is called inside loops `while (mask > 0)`, ensuring mask is non-zero. // So we don't need to worry about mask=0 case here. // If it were possible, we might return a special value like -1 or handle it explicitly. return 0; // Default return, should not be reached for non-zero mask } #define custom_ctz(x) (int)msvc_bsf_ulong((unsigned long)(x)) // Define custom_popcount equivalent for MSVC #define custom_popcount(x) (int)__popcnt((unsigned int)(x)) #else // Fallback implementations if no specific intrinsics are detected/available // This implementation of ctz finds the index of the least significant bit int fallback_ctz(int mask) { if (mask == 0) return 0; // Define behavior for 0 mask, though likely unused here int count = 0; // Check bits from right to left (0-indexed) while ((mask & 1) == 0) { mask >>= 1; count++; // Add safety break for potentially large integers, though int is usually 32 bits if (count >= 32) return -1; // Indicate error or handle appropriately } return count; } // This implementation of popcount counts the number of set bits int fallback_popcount(int mask) { int count = 0; while (mask > 0) { mask &= (mask - 1); // This clears the least significant set bit count++; } return count; } #define custom_ctz(x) fallback_ctz(x) #define custom_popcount(x) fallback_popcount(x) #endif using namespace std; int N; // Number of cards per player double PA, PB; // Probabilities for A and B to play their smallest card vector<int> A_sorted, B_sorted; // Sorted lists of initial cards for A and B // Using unordered_map for memoization. Key is a combination of two masks. // Key type is long long to accommodate up to 40 bits (20 for each player). unordered_map<long long, double> memo; // Recursive function to calculate expected score with memoization double dp(int mask_A, int mask_B) { // Base case: if no cards are left, expected score is 0 if (mask_A == 0) { return 0.0; } // Create a unique key for the current state (mask_A, mask_B) // Shift mask_A left by 20 bits (since N <= 20) and OR with mask_B long long state_key = ((long long)mask_A << 20) | mask_B; // Check if the result for this state is already memoized auto it = memo.find(state_key); if (it != memo.end()) { return it->second; // Return cached result } // Calculate the number of cards remaining for each player (k) int k = custom_popcount(mask_A); // Find the indices of the minimum value cards currently held by A and B // This relies on the cards being sorted initially. The LSB set in the mask corresponds to the minimum available card. int min_A_idx = custom_ctz(mask_A); int min_B_idx = custom_ctz(mask_B); double expected_value = 0.0; // Accumulator for the expected score from this state // Calculate the probability of playing a non-minimum card // Handle the case k=1 separately to avoid division by zero double prob_A_other = (k <= 1) ? 0.0 : (1.0 - PA) / (double)(k - 1.0); double prob_B_other = (k <= 1) ? 0.0 : (1.0 - PB) / (double)(k - 1.0); // Iterate through all possible cards A can play using bit manipulation // This loop iterates through each set bit in mask_A int current_mask_A = mask_A; while (current_mask_A > 0) { // Get the index 'i' of the least significant set bit (current card A to consider) int i = custom_ctz(current_mask_A); int card_A = A_sorted[i]; // Get the actual card value double prob_A; // Probability A plays this card // Determine the probability A plays card_A based on the rules if (k == 1) { // If only one card left, must play it prob_A = 1.0; } else { // Otherwise, depends if it's the minimum card prob_A = (i == min_A_idx) ? PA : prob_A_other; } // Iterate through all possible cards B can play using bit manipulation int current_mask_B = mask_B; while (current_mask_B > 0) { // Get the index 'j' of the least significant set bit (current card B to consider) int j = custom_ctz(current_mask_B); int card_B = B_sorted[j]; // Get the actual card value double prob_B; // Probability B plays this card // Determine the probability B plays card_B based on the rules if (k == 1) { // If only one card left, must play it prob_B = 1.0; } else { // Otherwise, depends if it's the minimum card prob_B = (j == min_B_idx) ? PB : prob_B_other; } // Calculate the score A gets in this specific match if A wins (card_A > card_B) double current_score = (card_A > card_B) ? (double)(card_A + card_B) : 0.0; // Determine the masks for the next state by removing the played cards // Use XOR to toggle the bit corresponding to the played card's index int next_mask_A = mask_A ^ (1 << i); int next_mask_B = mask_B ^ (1 << j); // Recursively call dp for the next state and add the weighted contribution // The total expected score is the immediate score + expected future score expected_value += prob_A * prob_B * (current_score + dp(next_mask_A, next_mask_B)); // Clear the least significant set bit in current_mask_B to move to the next card for B current_mask_B &= current_mask_B - 1; } // Clear the least significant set bit in current_mask_A to move to the next card for A current_mask_A &= current_mask_A - 1; } // Store the computed expected value in the memoization table before returning return memo[state_key] = expected_value; } int main() { // Use fast I/O operations ios_base::sync_with_stdio(false); cin.tie(NULL); // Read input values N, PA, PB cin >> N >> PA >> PB; // Read card values for players A and B vector<int> A_cards(N), B_cards(N); for (int i = 0; i < N; ++i) cin >> A_cards[i]; for (int i = 0; i < N; ++i) cin >> B_cards[i]; // Create sorted copies of the card lists A_sorted = A_cards; B_sorted = B_cards; sort(A_sorted.begin(), A_sorted.end()); sort(B_sorted.begin(), B_sorted.end()); // Calculate the initial mask where all bits are set (representing all cards available) // (1 << N) - 1 creates a mask with N set bits: 11...1 (N times) int initial_mask = (1 << N) - 1; // Call the recursive DP function starting from the initial state (all cards available) double result = dp(initial_mask, initial_mask); // Output the final result with the required precision cout << fixed << setprecision(15) << result << endl; return 0; }