結果

問題 No.3112 Decrement or Mod Game
ユーザー aaaaaaaaaaa
提出日時 2025-04-19 11:13:17
言語 C++17
(gcc 13.3.0 + boost 1.87.0)
結果
MLE  
実行時間 -
コード長 6,067 bytes
コンパイル時間 1,462 ms
コンパイル使用メモリ 91,400 KB
実行使用メモリ 814,592 KB
最終ジャッジ日時 2025-04-19 11:13:22
合計ジャッジ時間 5,468 ms
ジャッジサーバーID
(参考情報)
judge4 / judge1
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
sample -- * 3
other MLE * 1 -- * 64
権限があれば一括ダウンロードができます

ソースコード

diff #

#include <iostream>
#include <unordered_map>
#include <tuple>
#include <functional> // For std::hash

using namespace std;

// Custom hash for tuple<long long, long long, bool> for unordered_map
struct TupleHash {
    size_t operator()(const tuple<long long, long long, bool>& t) const {
        auto hash1 = hash<long long>{}(get<0>(t));
        auto hash2 = hash<long long>{}(get<1>(t));
        auto hash3 = hash<bool>{}(get<2>(t));

        // Simple combination of hashes - can be improved for better distribution
        size_t seed = 0;
        seed ^= hash1 + 0x9e3779b9 + (seed << 6) + (seed >> 2);
        seed ^= hash2 + 0x9e3779b9 + (seed << 6) + (seed >> 2);
        seed ^= hash3 + 0x9e3779b9 + (seed << 6) + (seed >> 2);
        return seed;
    }
};

// Using unordered_map for memoization: key is tuple<Alice's number, Bob's number, is_Alice's_turn>
// unordered_map generally provides faster average time complexity for lookups and insertions
// compared to std::map, which can help with runtime performance.
unordered_map<tuple<long long, long long, bool>, bool, TupleHash> memo;

// Function to determine if the current player can win from state (a, b)
// a: Alice's number, b: Bob's number, is_alice_turn: true if Alice's turn, false if Bob's
// Returns: true if current player wins, false otherwise
bool solve(long long a, long long b, bool is_alice_turn) {
    // Base case: If either number is 0, the player whose turn it is *now* loses.
    // This is because the previous player successfully made their opponent's number zero.
    if (a == 0 || b == 0) {
        return false;
    }

    // Check if this state has been computed before using memoization
    tuple<long long, long long, bool> current_state = {a, b, is_alice_turn};
    if (memo.count(current_state)) {
        return memo[current_state];
    }

    bool can_win = false; // Assume the current player loses initially

    if (is_alice_turn) {
        // Alice's turn, she has 'a', Bob has 'b'.
        // Alice wins if any of her possible moves lead to a state where Bob loses.

        // Option 1: Alice subtracts 1 from her number (a). New state: (a-1, b). Bob faces (a-1, b).
        // This move is always possible if a > 0, which is true due to the base case.
        if (!solve(a - 1, b, false)) {
            can_win = true; // Alice wins if Bob loses from (a-1, b)
        }

        // Option 2: Alice applies modulo on her number (a % b), if a >= b. New state: (a%b, b). Bob faces (a%b, b).
        // Only evaluate this move if Alice hasn't already found a winning move (by subtraction).
        if (!can_win && a >= b) {
            // Immediate win condition by modulo: if a % b == 0 (and b > 0) or b == 1,
            // Alice's number becomes 0 (a%b = 0), state becomes (0, b).
            // Bob faces (0, b). Since 0 is present, Bob loses (base case). Alice wins.
            if (b == 1 || a % b == 0) {
                can_win = true; // Immediate win for Alice by modulo
            } else { // a%b > 0 and b > 1
                 // Optimization for a >= 2*b:
                 // If a is significantly larger than b, the outcome depends on the
                 // outcome of the game from (a%b, b) and the parity of the quotient a/b.
                 // This is a specific property derived from the game mechanics.
                 if (a >= 2 * b) {
                    // Alice wins if Bob loses from (a%b, b) OR if the quotient (a/b) is even.
                    can_win = (!solve(a % b, b, false)) || ((a / b) % 2 == 0);
                 } else { // a >= b && a < 2*b (Ratio is between 1 and 2), a%b != 0, b > 1
                     // Alice wins if Bob loses from (a%b, b)
                     if (!solve(a % b, b, false)) {
                         can_win = true;
                     }
                 }
            }
        }

    } else { // Bob's turn, he has 'b', opponent Alice has 'a'. Symmetric logic.
        // Bob wins if any of his possible moves lead to a state where Alice loses.

        // Option 1: Bob subtracts 1 from his number (b). New state: (a, b-1). Alice faces (a, b-1).
        // This move is always possible if b > 0, which is true due to the base case.
         if (!solve(a, b - 1, true)) {
            can_win = true; // Bob wins if Alice loses from (a, b-1)
         }

        // Option 2: Bob applies modulo on his number (b % a), if b >= a. New state: (a, b%a). Alice faces (a, b%a).
        // Only evaluate this move if Bob hasn't already found a winning move (by subtraction).
         if (!can_win && b >= a) {
            // Immediate win condition by modulo: if b % a == 0 (and a > 0) or a == 1,
            // Bob's number becomes 0 (b%a = 0), state becomes (a, 0).
            // Alice faces (a, 0). Since 0 is present, Alice loses (base case). Bob wins.
            if (a == 1 || b % a == 0) {
                can_win = true; // Immediate win for Bob by modulo
            } else { // b%a > 0 and a > 1
                 // Optimization for b >= 2*a:
                 // Symmetric property for Bob's turn.
                 if (b >= 2 * a) {
                    // Bob wins if Alice loses from (a, b%a) OR if the quotient (b/a) is even.
                    can_win = (!solve(a, b % a, true)) || ((b / a) % 2 == 0);
                 } else { // b >= a && b < 2*a (Ratio is between 1 and 2), b%a != 0, a > 1
                     // Bob wins if Alice loses from (a, b%a)
                     if (!solve(a, b % a, true)) {
                         can_win = true;
                     }
                 }
            }
        }
    }

    // Memoize the result for the current state before returning
    memo[current_state] = can_win;

    return can_win;
}

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

    long long A, B;
    cin >> A >> B;

    // Determine if Alice wins starting from state (A, B) on her turn
    if (solve(A, B, true)) {
        cout << "Alice" << endl;
    } else {
        cout << "Bob" << endl;
    }

    return 0;
}
0