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
- State Definition: The game state is completely determined by “the range of remaining cards \([i, j]\)”.
- 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])\).
- 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
dpas shown in the provided code, memory usage is greatly reduced.Execution Speed Optimization: In Python, using
ifstatements for comparison can be faster than calling the built-inmax()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.
投稿日時:
最終更新: