CF 1147C - Thanos Nim

We are asked to analyze a two-player game played on an array of piles, each containing some number of stones. There are $n$ piles, and $n$ is guaranteed to be even.

CF 1147C - Thanos Nim

Rating: 2000
Tags: games
Solve time: 1m 22s
Verified: yes

Solution

Problem Understanding

We are asked to analyze a two-player game played on an array of piles, each containing some number of stones. There are $n$ piles, and $n$ is guaranteed to be even. Alice moves first, and on each turn a player must choose exactly $n/2$ nonempty piles and remove at least one stone from each of them. Players alternate turns until someone cannot make a move, which happens when fewer than $n/2$ piles are nonempty. The player who cannot move loses.

The input gives the number of piles $n$ and the array $a_1, a_2, \dots, a_n$ representing stones in each pile. The output should be the winner, either "Alice" or "Bob".

Constraints are small: $n$ goes up to 50 and each $a_i$ is up to 50. This allows algorithms that are quadratic in $n$ or even cubic if necessary. However, the game is combinatorial, so brute-forcing all moves would require examining $\binom{n}{n/2}$ choices at each step, which grows rapidly and is infeasible even for $n=50$.

Edge cases arise in situations where the piles are all equal, or there is a huge disparity between the largest and smallest piles. For example, if $n=2$ and both piles are equal, the second player can always mirror the first, guaranteeing a win. Careless implementations might miss the symmetry property and predict the wrong winner.

Approaches

A naive approach would simulate every possible move: for each player, generate all combinations of $n/2$ nonempty piles and subtract every possible number of stones from each chosen pile recursively until a terminal position is reached. This is correct because it explores all possibilities, but it is exponential in time complexity, specifically $O\left((\text{max stones})^{n/2} \cdot \binom{n}{n/2}\right)$, which is clearly infeasible for $n=50$.

The key insight comes from observing that the game is symmetric and can be reduced to comparing piles instead of simulating moves. Since each player must take $n/2$ piles, the game is equivalent to pairing the largest $n/2$ piles against the smallest $n/2$ piles. If the sum of the largest $n/2$ piles is strictly greater than the sum of the smallest $n/2$ piles, the first player can always remove stones in such a way to maintain advantage, otherwise, the second player can mirror moves to force a win. This allows a simple, linear-time solution: sort the piles and compare the sums of the two halves.

Approach Time Complexity Space Complexity Verdict
Brute Force O((50)^(n/2) * C(n, n/2)) O(n) Too slow
Optimal O(n log n) O(n) Accepted

Algorithm Walkthrough

  1. Read the number of piles $n$ and the array of pile sizes $a$.

Sorting and manipulation will be easier with the list in hand. 2. Sort the array $a$ in non-decreasing order.

Sorting ensures that the first $n/2$ elements are the smallest piles, and the last $n/2$ elements are the largest piles. 3. Compute the sum of the first $n/2$ piles (smallest) and the sum of the last $n/2$ piles (largest).

Let small_sum be the sum of the smallest $n/2$ piles, and large_sum be the sum of the largest $n/2$ piles. 4. Compare large_sum and small_sum.

If large_sum is greater, Alice has a winning strategy: she can always choose the largest piles and reduce them to maintain a strict advantage, eventually leaving Bob without a move. Otherwise, Bob can mirror Alice's moves to maintain equality and win. 5. Output "Alice" if large_sum > small_sum; otherwise, output "Bob".

Why it works: By always choosing the largest available piles, the first player can force a position where the second player faces fewer options. Sorting and splitting into halves creates a clear separation: if the total stones in the top half exceed the bottom half, the first player can always maintain control. This reduces the complex combinatorial game to a simple arithmetic comparison.

Python Solution

import sys
input = sys.stdin.readline

n = int(input())
a = list(map(int, input().split()))

a.sort()
half = n // 2

small_sum = sum(a[:half])
large_sum = sum(a[half:])

if large_sum > small_sum:
    print("Alice")
else:
    print("Bob")

The code reads input using fast I/O. Sorting the array ensures that the top half and bottom half are correctly identified. Computing the sums and comparing them directly implements the optimal strategy. There are no off-by-one errors because Python's slice a[:half] and a[half:] split the array exactly in half for even $n$.

Worked Examples

Example 1

Input:

2
8 8
Step Sorted Array small_sum large_sum Decision
Initial [8, 8] 8 8 8 > 8? No -> Bob

This demonstrates a tie in sums, so Alice cannot force a win; mirroring ensures Bob wins.

Example 2

Input:

4
1 2 3 4
Step Sorted Array small_sum large_sum Decision
Initial [1, 2, 3, 4] 1+2=3 3+4=7 7 > 3? Yes -> Alice

Alice can always select the two largest piles to maintain a winning advantage.

Complexity Analysis

Measure Complexity Explanation
Time O(n log n) Sorting dominates; n ≤ 50
Space O(n) Storing the array and slices

Given the constraints, n ≤ 50, this algorithm is extremely fast and well within memory limits.

Test Cases

import sys, io

def run(inp: str) -> str:
    sys.stdin = io.StringIO(inp)
    n = int(input())
    a = list(map(int, input().split()))
    a.sort()
    half = n // 2
    return "Alice" if sum(a[half:]) > sum(a[:half]) else "Bob"

# Provided samples
assert run("2\n8 8\n") == "Bob", "sample 1"
assert run("4\n1 2 3 4\n") == "Alice", "sample 2"

# Custom cases
assert run("2\n1 2\n") == "Alice", "first player has advantage"
assert run("4\n5 5 5 5\n") == "Bob", "all equal piles"
assert run("6\n1 1 1 1 10 10\n") == "Alice", "large disparity favors first"
assert run("50\n" + " ".join(["1"]*50) + "\n") == "Bob", "max n, equal stones"
Test input Expected output What it validates
2\n1 2\n Alice Smallest case with advantage
4\n5 5 5 5\n Bob Symmetry edge case
6\n1 1 1 1 10 10\n Alice Large disparity check
50\n1 ... 1\n Bob Maximum n with equal stones

Edge Cases

If all piles are equal, the algorithm correctly outputs "Bob". For example, n=4, a=[5,5,5,5]. Sums of top and bottom halves are equal, so Alice cannot maintain advantage. The slice computation a[:half] and a[half:] guarantees correct partitioning. If a single pile dominates, like n=6, a=[1,1,1,1,10,10], sorting ensures that the largest piles are considered by Alice, and the sum comparison correctly identifies her winning strategy.