Search for a command to run...
Progressive hints first, then the full explanation and implementation when you're ready to cash out.
Review status
AI-generated and still unreviewed. Double-check the details before internalizing them.
Hints
Open only as much as you need to keep the solve alive.
Group equal values together. If elements are currently equal to , choosing gives points and moves that whole bucket to .
First solve the boring case: if every current value is even, the player who moves second can always answer with and get the same bucket size. After those two moves, all values are even again.
So even values are just fair paired moves. The only “extra” points come from buckets whose value is odd, because choosing an odd value turns it into an even value and removes one unpaired bonus bucket.
Choosing an even value while odd buckets exist does not create a useful advantage. The opponent can immediately take the odd value below it; at best your move was neutral, and at worst you just fattened their odd bucket. Brutal, but fair.
Therefore the real game is just an alternating draft of the frequencies of initially odd values. Count each odd value’s frequency, sort those frequencies descending, give Alice the 1st, 3rd, 5th, ... and Bob the 2nd, 4th, 6th, ...; split all remaining points evenly.
Let be the number of elements currently equal to . A move on gives points, then moves that whole bucket to .
The important part is not the actual values as much as their parity.
All-even states are fair
Suppose every positive value in the array is even, and some player chooses an even value with bucket size .
After the move, those elements become , which is odd. Since the state had no odd values before, the opponent can choose immediately and also score exactly .
Then those elements become , which is even again. So after two moves:
Repeat this forever. So from an all-even state, the rest of the game gives equal points to both players, no matter whose turn it is.
That means all even layers are basically accounting noise. They split evenly.
Odd buckets are the only bonuses
Now look at an odd value with frequency .
If a player chooses this bucket, they get points and the bucket moves to , which is even. After that, this bucket belongs to the fair all-even machinery unless it interacts with other choices later. The key is: the unpaired bonus from this odd bucket has been claimed.
So every initially odd value contributes one prize equal to its frequency.
For example, if the odd values have frequencies , then those are the only contested bonus chunks. Everything else is split evenly like a tax form, sadly but cleanly.
Why not choose an even value first?
This is the tempting false move.
Say a player chooses an even value with bucket size . It moves to odd value .
If there was already an odd bucket there with size , the opponent can now choose and score . The cancels the first player’s , and the opponent also gets the odd bonus . So the first player just handed over value. Nice job, genius.
If there was no odd bucket there, the opponent can still choose and score , making the pair neutral. That does not improve anything; it just burns two moves and returns to the same kind of decision.
So optimal play can be described as: while odd buckets exist, players choose odd buckets.
The reduced game
Now the game is simple:
For independent positive prizes, optimal play is just picking the largest remaining prize each turn. If Alice skips the largest one, Bob takes it. No galaxy-brain nonsense needed.
So:
Let
This is Alice’s final score minus Bob’s final score.
Let
be the total number of points awarded in the whole game. Then:
The parity works out because both and have the same parity: even-valued elements do not affect parity, and each odd element contributes once to the odd-frequency total.
Complexity is per test case from sorting the odd frequencies, with total . Easy fit.
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
int main() {
setIO();
int T;
cin >> T;
while (T--) {
int n;
cin >> n;
ll total = 0;
map<ll, ll> odd_freq;
for (int i = 0; i < n; i++) {
ll x;
cin >> x;
total += x;
if (x & 1) odd_freq[x]++;
}
vector<ll> bonus;
for (auto [value, freq] : odd_freq) {
bonus.push_back(freq);
}
sort(bonus.rbegin(), bonus.rend());
ll diff = 0;
for (int i = 0; i < (int)bonus.size(); i++) {
if (i & 1) diff -= bonus[i];
else diff += bonus[i];
}
ll alice = (total + diff) / 2;
ll bob = (total - diff) / 2;
cout << alice << ' ' << bob << '\n';
}
return 0;
}#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
int main() {
setIO();
int T;
cin >> T;
while (T--) {
int n;
cin >> n;
ll total = 0;
map<ll, ll> odd_freq;
for (int i = 0; i < n; i++) {
ll x;
cin >> x;
total += x;
if (x & 1) odd_freq[x]++;
}
vector<ll> bonus;
for (auto [value, freq] : odd_freq) {
bonus.push_back(freq);
}
sort(bonus.rbegin(), bonus.rend());
ll diff = 0;
for (int i = 0; i < (int)bonus.size(); i++) {
if (i & 1) diff -= bonus[i];
else diff += bonus[i];
}
ll alice = (total + diff) / 2;
ll bob = (total - diff) / 2;
cout << alice << ' ' << bob << '\n';
}
return 0;
}