公式

D - カード取りゲーム / Card Taking Game 解説 by admin

Gemini 3.0 Flash (Thinking)

Overview

This problem involves a game where two players take turns picking cards from either end of a sequence. Both players play optimally to maximize their own score, and we need to find “(first player’s total score) - (second player’s total score)”.

Analysis

This game has properties similar to a “zero-sum game”, where an increase in one player’s score means a relative decrease in the other player’s score. For such games, dynamic programming (DP) is an effective approach, solving smaller subproblems first and building up to the full solution.

Key Observations

  1. State Definition: The game state is completely determined by “the range of remaining cards \([i, j]\)”.
  2. Objective Function: The current player wants to maximize “(my score) - (opponent’s score)”.
    • In the range \([i, j]\), if the current player takes the left end \(V_i\), the resulting difference becomes \(V_i - (\text{maximum difference from the opponent's perspective in range } [i+1, j])\).
    • Similarly, if the player takes the right end \(V_j\), the result is \(V_j - (\text{maximum difference from the opponent's perspective in range } [i, j-1])\).
  3. Optimal Strategy: The player chooses whichever of the two options yields the larger value.

With naive recursion (exhaustive search), there are \(2^N\) ways to pick cards, which is far too slow for \(N=3000\). However, there are only \(N^2\) possible card ranges \([i, j]\), so by reusing previously computed results through DP, we can solve the problem efficiently.

Algorithm

Dynamic Programming

We define the following DP table: - \(dp[i][j]\): When the remaining cards range from \(V_i\) to \(V_j\), the maximum value of “(current player’s total score) - (opponent’s total score)” that the current player can achieve.

Transition: - When there is only one card (base case): \(dp[i][i] = V_i\) - When there are multiple cards (length \(L = j - i + 1\)): \(dp[i][j] = \max(V_i - dp[i+1][j], \quad V_j - dp[i][j-1])\)

We compute this in order of increasing card range length \(L\) from \(1\) to \(N\). The final answer is \(dp[0][N-1]\).

Complexity

  • Time Complexity: \(O(N^2)\) There are \(N(N+1)/2\) possible card range combinations (states), and each transition is computed in \(O(1)\). For \(N=3000\), this results in approximately \(4.5 \times 10^6\) computations, which comfortably fits within the time limit.
  • Space Complexity: \(O(N)\) A straightforward implementation requires \(O(N^2)\) memory, but since computing length \(L\) only requires the results from length \(L-1\), we can reuse a single one-dimensional array to reduce memory to \(O(N)\).

Implementation Notes

  • Memory Optimization: For \(N=3000\), allocating a \(3000 \times 3000\) two-dimensional array consumes a significant amount of memory. By updating a one-dimensional array dp as shown in the provided code, memory usage is greatly reduced.

  • Execution Speed Optimization: In Python, using if statements for comparison can be faster than calling the built-in max() function. This difference can noticeably affect execution time, especially in inner loops with \(O(N^2)\) iterations.

  • Fast I/O: Using sys.stdin.read().split() reads all input at once, speeding up the input processing.

    Source Code

import sys

def main():
    # Read all input at once for efficiency. sys.stdin.read().split() 
    # splits the input into a list of strings by whitespace.
    input_data = sys.stdin.read().split()
    if not input_data:
        return
    
    # N is the number of cards.
    # V is the list of integers written on the cards.
    n = int(input_data[0])
    v = list(map(int, input_data[1:]))
    
    # We use a Dynamic Programming approach to solve this minimax game.
    # Let f(i, j) be the maximum value of (current player's sum - opponent's sum)
    # for the cards in the range [i, j].
    # The base case is when only one card is left: f(i, i) = V[i].
    # For a range [i, j], the current player can pick either V[i] or V[j].
    # If they pick V[i], the difference becomes V[i] - f(i+1, j).
    # If they pick V[j], the difference becomes V[j] - f(i, j-1).
    # Each player acts optimally to maximize this difference.
    
    # dp[i] will store the result for a subarray of the current 'length'
    # starting at index i. This allows us to use O(N) space.
    # Initialize the DP table for length 1.
    dp = list(v)
    
    # Iterate through possible lengths of subarrays from 2 up to N.
    for length in range(2, n + 1):
        # offset represents the distance from the left index i to the right index j.
        offset = length - 1
        
        # Calculate the DP value for each subarray of the current length.
        # We update the dp array in-place. dp[i] for 'length' is calculated 
        # using dp[i] and dp[i+1] from 'length - 1'.
        for i in range(n - length + 1):
            # Option 1: Pick the leftmost card v[i].
            # Option 2: Pick the rightmost card v[i + offset].
            
            # Use a simple if-else instead of the max() function for a slight performance gain in Python.
            opt_left = v[i] - dp[i + 1]
            opt_right = v[i + offset] - dp[i]
            
            if opt_left > opt_right:
                dp[i] = opt_left
            else:
                dp[i] = opt_right
                
    # The final answer is the maximum difference for the full array (length N) starting at index 0.
    print(dp[0])

if __name__ == '__main__':
    main()

This editorial was generated by gemini-3-flash-thinking.

投稿日時:
最終更新: