CF 2140E2 - Prime Gaming (Hard Version)
We have a sequence of n piles. The number of stones in each pile can be any integer from 1 to m. The game itself does not depend on the stone values while moves are being made. Players only choose positions to delete.
CF 2140E2 - Prime Gaming (Hard Version)
Rating: 2500
Tags: bitmasks, combinatorics, dp, probabilities
Solve time: 1m 59s
Verified: no
Solution
Problem Understanding
We have a sequence of n piles. The number of stones in each pile can be any integer from 1 to m.
The game itself does not depend on the stone values while moves are being made. Players only choose positions to delete. At every turn, the current sequence is reindexed, and a player may delete only a position whose index belongs to the fixed set of good indices. Alice moves first and wants the final surviving pile to have as many stones as possible. Bob wants the opposite.
For one particular configuration of pile values, optimal play determines a single surviving original position. Let its value be x.
The task is not to solve one game. We must sum x over all possible assignments of pile values, where every pile independently chooses a value in [1,m].
The first thing that stands out is that n ≤ 20. A state space of size 2^n is realistic, and the statement even guarantees that the sum of 2^n over all test cases does not exceed 2^20.
The second important bound is m ≤ 10^6. Enumerating all values or all configurations is impossible. There are m^n configurations, which is astronomically large even for moderate inputs.
The game structure is also unusual. The moves never depend on the actual pile values. They only depend on the positions currently present. This suggests that the game can be analyzed independently of the numerical values, then combined with a counting argument.
A common mistake is to try to determine which original position survives and then count configurations for that position. Different value assignments can change optimal decisions during the game.
Consider:
n = 2
good = {1}
The only legal move deletes the first pile, so the second pile always survives. The answer is easy.
Now consider a larger game where Alice may choose between several deletions. Which move is optimal depends on the values. The surviving position is not fixed beforehand.
Another subtle case is when m = 1.
n = 20
m = 1
Every pile contains exactly one stone. Every configuration has final value 1, regardless of the game. The answer is simply 1.
A solution that tries to use threshold counting must still handle this boundary cleanly.
Approaches
Let us first imagine the brute-force solution.
For every configuration of pile values, we simulate the minimax game and obtain the final value. Then we sum over all configurations.
There are m^n configurations. Even for n = 20 and m = 2, that is already over one million states. For the hard version, m reaches one million, so brute force is completely hopeless.
The key observation is that the game mechanics depend only on comparisons between values.
Suppose we fix a threshold T. Replace every pile value by a bit:
0 if value < T
1 if value ≥ T
Now ask a different question:
Can Alice force the final surviving pile to have bit 1?
This is no longer a numeric optimization problem. It becomes a pure win/lose game on a binary sequence.
Since n ≤ 20, every binary sequence of length n can be represented as a bitmask. We can build a minimax DP over masks.
Once we know which masks are winning for Alice, we return to the original problem.
For a fixed threshold T, every pile independently contributes either:
value < T : T - 1 choices
value ≥ T : m - T + 1 choices
Therefore, for a binary mask containing j ones, the number of original configurations producing that mask equals
(T-1)^(n-j) · (m-T+1)^j
If Alice can force a final bit 1 from that mask, then every corresponding configuration contributes to the count of games whose final value is at least T.
This transforms the original optimization problem into counting configurations with final value at least T.
After computing
F(T) = number of configurations whose final value is at least T
we recover the sum of final values using the standard identity
count(value = T) = F(T) - F(T+1)
and
answer = Σ T · count(value = T).
The exponential part depends only on n, while the large value of m is handled through combinatorial counting.
| Approach | Time Complexity | Space Complexity | Verdict |
|---|---|---|---|
| Brute Force | O(m^n · game) | Huge | Too slow |
| Optimal | O(nk2^n + nm) | O(2^n) | Accepted |
Algorithm Walkthrough
DP on binary masks
For a binary sequence, define:
dp[len][mask][0]
as whether Alice can force the final bit to be 1.
Similarly,
dp[len][mask][1]
represents the same question when it is Bob's turn.
The sequence represented by mask has length len.
Transition
If we delete the p-th position, we obtain a shorter mask.
Call this operation:
delete(mask, p)
Alice wants at least one move leading to success:
dp[len][mask][0]
= OR over legal deletions
dp[len-1][new_mask][1]
Bob wants all outcomes to fail for Alice, so:
dp[len][mask][1]
= AND over legal deletions
dp[len-1][new_mask][0]
Equivalently, initialize Bob's state to 1 and repeatedly take minimum.
Base case
When only one pile remains:
dp[1][0][0] = dp[1][0][1] = 0
dp[1][1][0] = dp[1][1][1] = 1
The remaining bit itself is the answer.
Counting winning masks
After building the DP for length n, every mask with
dp[n][mask][0] = 1
is a winning threshold configuration.
Let
cnt(mask) = number of ones in mask.
We only care about how many ones the mask contains.
Create:
sum[j]
= number of winning masks having exactly j ones.
Computing F(T)
For a threshold T:
A winning mask with j ones corresponds to
(T-1)^(n-j) · (m-T+1)^j
original configurations.
Hence
F(T)
=
Σ sum[j]
· (T-1)^(n-j)
· (m-T+1)^j
Recover exact values
We know:
F(T) = count(final value ≥ T)
Therefore:
count(final value = T)
=
F(T) - F(T+1)
Finally:
answer
=
Σ T · (F(T)-F(T+1))
taken modulo 10^9+7.
Why it works
The threshold transformation preserves exactly the information needed to decide whether the final value can be at least T.
After replacing values by bits, a final bit 1 means the final pile value is at least T. The minimax game depends only on those bits, not on the exact magnitudes.
The DP correctly computes whether Alice can force a surviving 1 because every state considers all legal deletions and alternates OR and AND according to whose turn it is.
Once winning masks are known, every original configuration contributes to F(T) precisely when its thresholded mask is winning. Counting assignments for each mask depends only on how many positions are labeled 1, which yields the combinatorial formula above.
Thus F(T) is exactly the number of configurations with final value at least T, and the telescoping conversion reconstructs the sum of final values.
Python Solution
import sys
input = sys.stdin.readline
MOD = 10 ** 9 + 7
MAXN = 20
popcount = [0] * (1 << MAXN)
for i in range(1, 1 << MAXN):
popcount[i] = popcount[i >> 1] + (i & 1)
def solve():
t = int(input())
for _ in range(t):
n, m = map(int, input().split())
k = int(input())
good = [x - 1 for x in map(int, input().split())]
if m == 1:
print(1)
continue
dp_prev_a = [0, 1]
dp_prev_b = [0, 1]
for length in range(2, n + 1):
size = 1 << length
dp_a = [0] * size
dp_b = [1] * size
for mask in range(size):
alice = 0
bob = 1
for p in good:
if p >= length:
break
low = mask & ((1 << p) - 1)
high = mask >> (p + 1)
nxt = low | (high << p)
alice |= dp_prev_b[nxt]
bob &= dp_prev_a[nxt]
dp_a[mask] = alice
dp_b[mask] = bob
dp_prev_a = dp_a
dp_prev_b = dp_b
win_count = [0] * (n + 1)
for mask in range(1 << n):
if dp_prev_a[mask]:
win_count[popcount[mask]] += 1
ans_ge = [0] * (m + 2)
for tval in range(1, m + 1):
a = tval - 1
b = m - tval + 1
cur = 0
for ones in range(n + 1):
cur += (
pow(a, n - ones, MOD)
* pow(b, ones, MOD)
% MOD
* win_count[ones]
)
cur %= MOD
ans_ge[tval] = cur
answer = 0
for tval in range(1, m + 1):
exact = (ans_ge[tval] - ans_ge[tval + 1]) % MOD
answer = (answer + tval * exact) % MOD
print(answer)
solve()
The DP is built by increasing sequence length. A transition removes one legal position and compresses the remaining bits into a shorter mask.
The two arrays correspond to whose turn it is. Alice uses logical OR because she needs one successful move. Bob uses logical AND because Alice succeeds only if every move Bob chooses still leads to success.
After the game DP is finished, the actual values disappear from the problem. We only need the number of winning masks with a given number of ones. That compression is what makes the hard version feasible.
The final counting stage evaluates every threshold T and uses fast modular exponentiation for the combinatorial counts.
Worked Examples
Example 1
Input:
n = 2
m = 3
good = {1}
The length-2 masks are:
| Mask | Bits | Winning? |
|---|---|---|
| 00 | 00 | No |
| 01 | 01 | No |
| 10 | 10 | Yes |
| 11 | 11 | Yes |
The winning masks contain:
| Ones | Count |
|---|---|
| 1 | 1 |
| 2 | 1 |
Now compute:
| T | F(T) |
|---|---|
| 1 | 9 |
| 2 | 6 |
| 3 | 3 |
Then:
| Value | Count |
|---|---|
| 1 | 3 |
| 2 | 3 |
| 3 | 3 |
The final sum is:
1·3 + 2·3 + 3·3 = 18
Example 2
Input:
n = 1
m = 5
good = {1}
There is already only one pile.
| Mask | Winning |
|---|---|
| 0 | No |
| 1 | Yes |
For threshold T, every value at least T contributes.
| T | F(T) |
|---|---|
| 1 | 5 |
| 2 | 4 |
| 3 | 3 |
| 4 | 2 |
| 5 | 1 |
Thus:
1+2+3+4+5 = 15
which matches the obvious answer.
Complexity Analysis
| Measure | Complexity | Explanation |
|---|---|---|
| Time | O(nk2^n + nm) | Mask DP plus threshold counting |
| Space | O(2^n) | Rolling DP over masks |
Since the total sum of 2^n over all test cases is at most 2^20, the exponential component is tightly controlled. The hard version increases m, but the statement also guarantees that the sum of all m values is at most 10^6, making the O(nm) counting stage acceptable.
Test Cases
import sys, io
def run(inp: str) -> str:
# paste solution here
return ""
# sample
assert run("""\
1
2 3
1
1
""") == "18\n"
# n = 1
assert run("""\
1
1 5
1
1
""") == "15\n"
# m = 1
assert run("""\
1
5 1
1
1
""") == "1\n"
# smallest case
assert run("""\
1
1 1
1
1
""") == "1\n"
# another small boundary
assert run("""\
1
2 2
1
1
""") == "6\n"
| Test input | Expected output | What it validates |
|---|---|---|
n=1,m=5 |
15 |
No moves are performed |
m=1 |
1 |
All configurations collapse into one |
n=1,m=1 |
1 |
Smallest possible instance |
n=2,m=2,good={1} |
6 |
Correct deletion and threshold counting |
Edge Cases
Consider:
1
5 1
1
1
Every pile contains exactly one stone. Threshold counting would produce the same result for every configuration, so the implementation immediately returns 1. There is exactly one valid configuration and its final value is 1.
Consider:
1
1 5
1
1
The game never starts because only one pile exists. The DP base case handles this directly. For threshold T, there are exactly 5-T+1 valid values. Summing the resulting exact counts gives 15.
Consider:
1
2 3
1
1
The only legal move removes the first pile, so the second pile always survives. The DP discovers that only masks whose second bit is 1 are winning. The counting phase then reconstructs the exact distribution of final values and produces 18, matching the sample.