結果

問題 No.973 余興
ユーザー qwewe
提出日時 2025-05-14 13:19:53
言語 C++17
(gcc 13.3.0 + boost 1.87.0)
結果
TLE  
実行時間 -
コード長 6,669 bytes
コンパイル時間 843 ms
コンパイル使用メモリ 81,748 KB
実行使用メモリ 7,848 KB
最終ジャッジ日時 2025-05-14 13:21:00
合計ジャッジ時間 10,927 ms
ジャッジサーバーID
(参考情報)
judge4 / judge3
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
sample -- * 2
other AC * 11 TLE * 1 -- * 42
権限があれば一括ダウンロードができます

ソースコード

diff #

#include <iostream>
#include <vector>
#include <numeric>

using namespace std;

// Define a constant for maximum N + padding, useful for array declarations if needed
// Using N+2 size arrays/vectors to handle boundary checks gracefully (indices L+k > N or R-k < 1)
const int MAXN_PADDED = 5005 + 2; 

// Global arrays for storing cream puff values and prefix sums
// Using 1-based indexing for easier mapping to problem statement indices L and R
long long a[MAXN_PADDED]; 
long long prefix_sum[MAXN_PADDED];

// DP table: win[L][R] will be true if the player whose turn it is can win starting from state [L, R]
// Otherwise, it will be false (meaning it's a losing state / P-position)
vector<vector<bool>> win; 

// Helper function to calculate the sum of nutritional values for cream puffs in range [l, r]
// Uses prefix sums for O(1) time calculation.
// Inline suggests the compiler to replace the function call with its body, potentially minor speedup.
inline long long get_sum(int l, int r) { // 1-based indices
    // If the range is invalid (left index > right index), the sum is 0
    if (l > r) return 0;
    // Calculate sum using precomputed prefix sums
    return prefix_sum[r] - prefix_sum[l - 1];
}

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

    int N; // Number of cream puffs
    long long X; // Maximum allowed calorie intake per turn
    cin >> N >> X;

    // Read nutritional values for each cream puff
    for (int i = 1; i <= N; ++i) {
        cin >> a[i];
    }

    // Calculate prefix sums for efficient range sum queries
    prefix_sum[0] = 0;
    for (int i = 1; i <= N; ++i) {
        prefix_sum[i] = prefix_sum[i - 1] + a[i];
    }

    // Initialize the DP table `win` with size (N+2) x (N+2)
    // All entries are initialized to false by default.
    // False represents a losing state (P-position). True represents a winning state (N-position).
    win.resize(N + 2, vector<bool>(N + 2, false));

    // Dynamic Programming approach: Iterate through all possible contiguous subsegments [L, R]
    // We compute the win/loss status for shorter segments first, building up to the full segment [1, N].
    // Outer loop iterates over the length of the subsegment.
    for (int length = 1; length <= N; ++length) {
        // Inner loop iterates over the starting position L of the subsegment.
        for (int L = 1; L <= N - length + 1; ++L) {
            int R = L + length - 1; // Calculate the ending position R based on L and length

            // Find k_max_L: the maximum number of cream puffs `k` that can be eaten from the left end (starting at L)
            // such that the total nutritional value does not exceed X.
            // We use a linear scan which is efficient if k_max_L is typically small.
            int k_max_L = 0;
            long long current_sum_L = 0;
            for (int k = 1; k <= length; ++k) {
                current_sum_L += a[L + k - 1]; // Add the next cream puff's value
                if (current_sum_L <= X) {
                    k_max_L = k; // Update max k if sum is within limit
                } else {
                    break; // Sum exceeds X, cannot eat more from this end
                }
            }
            
            // Find k_max_R: similar calculation for eating from the right end (starting at R).
            int k_max_R = 0;
            long long current_sum_R = 0;
             for (int k = 1; k <= length; ++k) {
                 current_sum_R += a[R - k + 1]; // Add the next cream puff's value (from right)
                 if (current_sum_R <= X) {
                     k_max_R = k; // Update max k
                 } else {
                     break; // Sum exceeds X
                 }
             }

            // Determine if the current state [L, R] is a winning state.
            // A state is winning if there exists at least one move to a losing state for the opponent.
            bool found_winning_move = false;

            // Check possible moves from the left end: eating k = 1 to k_max_L puffs.
            for (int k = 1; k <= k_max_L; ++k) {
                 int next_L = L + k; // New left index after eating k puffs
                 int next_R = R;     // Right index remains the same
                 
                 // Check if the move ends the game (results in an empty segment)
                 if (next_L > next_R) { 
                      // In misere play, the player making the move that empties the segment loses.
                      // Therefore, this is not a winning move for the current player.
                      continue; 
                 }
                 // If the resulting state [next_L, next_R] is a losing state for the opponent (!win[next_L][next_R]),
                 // then the current player has found a winning move.
                 if (!win[next_L][next_R]) { 
                      found_winning_move = true;
                      break; // Found a winning move, no need to check further moves from left
                 }
            }
            
            // If no winning move was found by eating from the left, check moves from the right end.
            if (!found_winning_move) {
                 // Check possible moves from the right end: eating k = 1 to k_max_R puffs.
                 for (int k = 1; k <= k_max_R; ++k) {
                     int next_L = L;     // Left index remains the same
                     int next_R = R - k; // New right index after eating k puffs
                     
                     // Check if the move ends the game
                     if (next_L > next_R) { 
                         // This move makes the current player lose. Not a winning move.
                         continue;
                     }
                     // If the resulting state [next_L, next_R] is a losing state for the opponent,
                     // then the current player has found a winning move.
                     if (!win[next_L][next_R]) {
                          found_winning_move = true;
                          break; // Found a winning move
                     }
                 }
            }
            
            // Update the DP table: state [L, R] is winning if a winning move was found.
            win[L][R] = found_winning_move;
        }
    }

    // The final result depends on the status of the initial state [1, N].
    // If win[1][N] is true, the first player (A) has a winning strategy.
    // Otherwise, the second player (B) has a winning strategy.
    if (win[1][N]) {
        cout << "A" << endl;
    } else {
        cout << "B" << endl;
    }

    return 0;
}
0