結果

問題 No.1004 サイコロの実装 (2)
ユーザー qwewe
提出日時 2025-05-14 13:07:34
言語 C++17
(gcc 13.3.0 + boost 1.87.0)
結果
WA  
実行時間 -
コード長 13,678 bytes
コンパイル時間 739 ms
コンパイル使用メモリ 86,508 KB
実行使用メモリ 7,844 KB
最終ジャッジ日時 2025-05-14 13:09:22
合計ジャッジ時間 2,043 ms
ジャッジサーバーID
(参考情報)
judge5 / judge3
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
sample AC * 2
other AC * 35 WA * 3
権限があれば一括ダウンロードができます

ソースコード

diff #

#include <iostream>
#include <vector>
#include <map>
#include <algorithm> // For std::min

// Use unsigned 32-bit integers for LCG state and parameters.
// This type automatically handles arithmetic modulo 2^32 due to overflow behavior.
using uint32 = unsigned int;
// Use unsigned 64-bit integers for counts and positions, as they can exceed 2^32.
using uint64 = unsigned long long;

// Structure for 2x2 matrix operations modulo 2^32.
// Used to efficiently compute the LCG state after many steps.
struct Matrix {
    uint32 mat[2][2];

    Matrix() {
        mat[0][0] = mat[0][1] = mat[1][0] = mat[1][1] = 0;
    }
};

// Matrix multiplication C = A * B, performed modulo 2^32.
Matrix multiply(const Matrix& A, const Matrix& B) {
    Matrix C;
    for (int i = 0; i < 2; ++i) {
        for (int j = 0; j < 2; ++j) {
            // Use uint64 for intermediate sum calculation to prevent overflow before the final modulo 2^32.
            // The product of two uint32 can reach (2^32-1)^2, which fits into uint64.
            // The sum of two such products can exceed uint64 capacity, but since we only need the result modulo 2^32,
            // casting the final sum to uint32 achieves this implicitly.
            uint64 sum = 0; 
            for (int k = 0; k < 2; ++k) {
                // Perform multiplications using uint64 to hold the possibly large intermediate product.
                sum = sum + (uint64)A.mat[i][k] * B.mat[k][j];
            }
            // Casting sum to uint32 effectively computes sum mod 2^32.
            C.mat[i][j] = (uint32)sum; 
        }
    }
    return C;
}

// Matrix power M^p using binary exponentiation (exponentiation by squaring).
// Computes M^p modulo 2^32 efficiently in O(log p) matrix multiplications.
Matrix matrix_pow(Matrix M, uint64 p) {
    Matrix res;
    // Initialize result matrix to identity matrix.
    res.mat[0][0] = 1; res.mat[1][1] = 1; 
    
    // Standard binary exponentiation algorithm.
    while (p > 0) {
        // If p is odd, multiply current result by M.
        if (p & 1) {
            res = multiply(res, M);
        }
        // Square M for the next iteration.
        M = multiply(M, M);
        // Halve p (integer division).
        p >>= 1;
    }
    return res;
}


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

    uint32 a, b, x0; // LCG parameters and initial seed.
    uint64 N; // Number of turns per player.
    std::cin >> a >> b >> x0 >> N;

    // Base case: If N=0, no turns are taken, scores are 0.
    if (N == 0) {
        std::cout << "0 0\n";
        return 0;
    }

    // Total turns in the game is 2*N.
    uint64 total_turns = 2 * N;

    // Game state variables: positions and stone counts for Takahashi (T) and Aoki (A).
    uint64 P_T = 0, P_A = 0; // Current positions.
    uint64 B_T = 0, W_T = 0; // Black and White stone counts for Takahashi.
    uint64 B_A = 0, W_A = 0; // Black and White stone counts for Aoki.
    
    // Find cycle in the sequence y_k = x_k mod 6.
    // This sequence determines the die rolls d_k = y_k + 1.
    std::map<uint32, uint64> visited_y; // Map to store {y_value -> first turn k it appeared}.
    uint32 y; // Current y_k value.
    uint64 k_cycle_found = 0; // Turn index when cycle is detected. 0 if not found within total_turns.
    uint64 mu = 0; // Length of the preperiod (transient part before cycle).
    uint64 lambda = 0; // Length of the cycle.
        
    // Simulate LCG to find cycle properties. Use a temporary variable for x state.
    uint32 temp_x = x0; 
    for (uint64 k = 1; k <= total_turns; ++k) {
        // Calculate next LCG state x_k.
        temp_x = a * temp_x + b; 
        // Calculate y_k = x_k mod 6.
        y = temp_x % 6;
        
        // Check if this y value has been seen before.
        if (visited_y.count(y)) { 
             // Cycle detected.
             k_cycle_found = k; // Record the turn index.
             mu = visited_y[y] - 1; // Preperiod length is steps before first occurrence.
             lambda = k - visited_y[y]; // Cycle length is difference in turn indices.
             break; // Exit loop once cycle is found.
        }
        // Store the first occurrence of this y value and its turn index.
        visited_y[y] = k;
        
        // If loop reaches total_turns without finding a cycle, it means the relevant part of the sequence fits entirely within the preperiod.
        if (k == total_turns) {
             mu = total_turns; // The entire sequence up to total_turns is considered preperiod.
             lambda = 0; // No cycle is relevant/used.
             k_cycle_found = k+1; // Set flag to indicate loop finished, treated as cycle found after end.
             break;
        }
    }

    // Simulate the preperiod phase (first mu steps).
    uint32 current_x = x0; // Initialize LCG state for actual game simulation.
    for (uint64 k = 1; k <= mu; ++k) {
        // Update LCG state.
        current_x = a * current_x + b;
        // Calculate die roll.
        uint32 roll = (current_x % 6) + 1;
        
        // Determine whose turn it is based on turn index k (odd for T, even for A).
        if (k % 2 != 0) { // Takahashi's turn
            P_T += roll; // Update position.
            // Check parity of new position and update stone counts.
            if (P_T % 2 != 0) B_T++; else W_T++; 
        } else { // Aoki's turn
            P_A += roll; // Update position.
            // Check parity and update stone counts.
            if (P_A % 2 != 0) B_A++; else W_A++;
        }
    }
    
    // Store the LCG state after the preperiod phase.
    uint32 x_mu = current_x; 

    // Calculate remaining turns after the preperiod.
    uint64 remaining_turns = total_turns - mu;
    
    // If there is a cycle (lambda > 0) and there are remaining turns:
    if (lambda > 0 && remaining_turns > 0) {
        // Calculate number of full cycles (q) and remaining steps within the last partial cycle (r).
        uint64 q = remaining_turns / lambda;
        uint64 r = remaining_turns % lambda;

        // Calculate the changes in state over one full cycle.
        // Simulate one cycle starting from a temporary state to find deltas.
        uint32 cycle_sim_x = x_mu; // Start LCG state from x_mu.
        uint64 cycle_delta_PT = 0, cycle_delta_PA = 0; // Position changes over one cycle.
        uint64 cycle_delta_BT0 = 0, cycle_delta_WT0 = 0; // Stone count changes assuming Player T starts cycle at even position.
        uint64 cycle_delta_BA0 = 0, cycle_delta_WA0 = 0; // Stone count changes assuming Player A starts cycle at even position.

        uint64 temp_PT = 0; // Use temporary positions starting at 0 to track parity for delta calculation.
        uint64 temp_PA = 0;

        // Simulate lambda steps to find cycle deltas.
        for (uint64 i = 1; i <= lambda; ++i) {
             cycle_sim_x = a * cycle_sim_x + b;
             uint32 roll = (cycle_sim_x % 6) + 1;
             
             uint64 current_turn_idx = mu + i; // Absolute turn index within the game.
             
             // Check whose turn based on absolute turn index.
             if (current_turn_idx % 2 != 0) { // Takahashi's turn
                 temp_PT += roll; // Update temporary position.
                 cycle_delta_PT += roll; // Accumulate position change.
                 // Accumulate stone counts based on temporary position's parity (assumes start even).
                 if (temp_PT % 2 != 0) cycle_delta_BT0++; else cycle_delta_WT0++;
             } else { // Aoki's turn
                 temp_PA += roll;
                 cycle_delta_PA += roll;
                 if (temp_PA % 2 != 0) cycle_delta_BA0++; else cycle_delta_WA0++;
             }
        }
       
        // Define the single step LCG transformation matrix M1 = {{a, b}, {0, 1}}.
        Matrix M1; 
        M1.mat[0][0] = a; M1.mat[0][1] = b;
        M1.mat[1][0] = 0; M1.mat[1][1] = 1;
        
        // Compute M^lambda, the transformation matrix over one cycle.
        Matrix M_lambda = matrix_pow(M1, lambda);
        
        // Compute (M^lambda)^q, the transformation over q full cycles.
        Matrix M_lambda_q = matrix_pow(M_lambda, q);
        
        // Update player positions based on total change over q cycles.
        P_T += q * cycle_delta_PT; 
        P_A += q * cycle_delta_PA;
        
        // Calculate total stone changes over q cycles, considering initial parity and parity change per cycle.
        uint64 total_delta_BT = 0, total_delta_WT = 0;
        uint64 total_delta_BA = 0, total_delta_WA = 0;

        // Check parity of Takahashi's position at the start of the cycles (after mu steps).
        bool P_T_parity_at_mu_is_odd = ( (mu == 0 ? 0 : P_T) % 2 != 0); // P_T is state after mu steps. If mu=0, initial P_T=0.
        // Check if Takahashi's position parity changes over one cycle.
        bool cycle_delta_PT_odd = (cycle_delta_PT % 2 != 0);

        // Calculate total stone changes for Takahashi over q cycles.
        if (!cycle_delta_PT_odd) { // If parity change is even, parity remains constant throughout cycles.
             if (!P_T_parity_at_mu_is_odd) { // Starts even.
                 total_delta_BT = q * cycle_delta_BT0;
                 total_delta_WT = q * cycle_delta_WT0;
             } else { // Starts odd. Stone collection swaps roles (B collected where W would be, etc.).
                 total_delta_BT = q * cycle_delta_WT0; // Use WT0 for BT count when starting odd.
                 total_delta_WT = q * cycle_delta_BT0; // Use BT0 for WT count when starting odd.
             }
        } else { // If parity change is odd, parity alternates each cycle.
             uint64 count_p1 = q / 2; // Number of cycles starting with parity 1-P_T_parity_at_mu_is_odd
             uint64 count_p0 = q - count_p1; // Number of cycles starting with parity P_T_parity_at_mu_is_odd

             if (!P_T_parity_at_mu_is_odd) { // Starts even (p0=0).
                 total_delta_BT = count_p0 * cycle_delta_BT0 + count_p1 * cycle_delta_WT0; // Sum contributions based on starting parity of each cycle.
                 total_delta_WT = count_p0 * cycle_delta_WT0 + count_p1 * cycle_delta_BT0;
             } else { // Starts odd (p0=1).
                 total_delta_BT = count_p0 * cycle_delta_WT0 + count_p1 * cycle_delta_BT0; // Contributions are swapped compared to starting even.
                 total_delta_WT = count_p0 * cycle_delta_BT0 + count_p1 * cycle_delta_WT0;
             }
        }

        // Repeat similar calculation for Aoki's stones.
        bool P_A_parity_at_mu_is_odd = ( (mu == 0 ? 0 : P_A) % 2 != 0); // Check Aoki's start parity after mu steps.
        bool cycle_delta_PA_odd = (cycle_delta_PA % 2 != 0); // Check parity change for Aoki over cycle.
        
        if (!cycle_delta_PA_odd) { // Constant parity for Aoki.
             if (!P_A_parity_at_mu_is_odd) { // Starts even.
                 total_delta_BA = q * cycle_delta_BA0;
                 total_delta_WA = q * cycle_delta_WA0;
             } else { // Starts odd.
                 total_delta_BA = q * cycle_delta_WA0;
                 total_delta_WA = q * cycle_delta_BA0;
             }
        } else { // Alternating parity for Aoki.
             uint64 count_p1 = q / 2; 
             uint64 count_p0 = q - count_p1; 

             if (!P_A_parity_at_mu_is_odd) { // Starts even.
                 total_delta_BA = count_p0 * cycle_delta_BA0 + count_p1 * cycle_delta_WA0;
                 total_delta_WA = count_p0 * cycle_delta_WA0 + count_p1 * cycle_delta_BA0;
             } else { // Starts odd.
                 total_delta_BA = count_p0 * cycle_delta_WA0 + count_p1 * cycle_delta_BA0;
                 total_delta_WA = count_p0 * cycle_delta_BA0 + count_p1 * cycle_delta_WA0;
             }
        }
        
        // Apply the calculated total stone changes to the game state.
        B_T += total_delta_BT;
        W_T += total_delta_WT;
        B_A += total_delta_BA;
        W_A += total_delta_WA;

        // Compute the LCG state after q full cycles using the computed matrix M_lambda_q.
        // x_{mu + q*lambda} = A' * x_mu + B' where M_lambda_q = {{A', B'}, {0, 1}}.
        uint32 A_prime = M_lambda_q.mat[0][0];
        uint32 B_prime = M_lambda_q.mat[0][1];
        // Need uint64 intermediate calculation for A' * x_mu + B' to avoid overflow before modulo 2^32.
        current_x = (uint32)((uint64)A_prime * x_mu + B_prime); 

        // Simulate the remaining r steps.
        for (uint64 i = 0; i < r; ++i) {
             // Update LCG state first for turn k = mu + q*lambda + i + 1.
             current_x = a * current_x + b; 
             uint32 roll = (current_x % 6) + 1;
             
             // Determine whose turn based on absolute turn index.
             uint64 current_turn_idx = mu + q * lambda + i + 1; 
             
             if (current_turn_idx % 2 != 0) { // Takahashi's turn
                 P_T += roll;
                 if (P_T % 2 != 0) B_T++; else W_T++;
             } else { // Aoki's turn
                 P_A += roll;
                 if (P_A % 2 != 0) B_A++; else W_A++;
             }
        }
    } 
    // If lambda=0 (no cycle found within total_turns) or remaining_turns=0, 
    // the simulation is effectively complete after the mu steps. No further action needed in this block.
    
    // Calculate final scores: minimum of black and white stones for each player.
    uint64 score_T = std::min(B_T, W_T);
    uint64 score_A = std::min(B_A, W_A);

    // Output the scores.
    std::cout << score_T << " " << score_A << "\n";

    return 0;
}
0