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.
Turn the answer into a yes/no question. For a target value , ask whether Alex can force the final beauty to be at least .
For this fixed , build a graph on indices. Put an edge between exactly when . Alex wins the threshold game iff he manages to lock both endpoints of some edge.
Now look at the easier game where Alex moves first. If some vertex has degree at least , Alex locks it, Hao can remove only one neighbor, and Alex locks another neighbor next. Boom, edge completed.
If every degree is at most , the graph is just a matching plus isolated vertices. Then Hao can always answer Alex locking one endpoint by removing its matched partner, so Alex never completes an edge.
So in the real game, Hao’s first move must delete one index so that the remaining graph has maximum degree at most . You only need degrees capped at : compute them in by keeping the three smallest previous values and the three largest future values.
Let’s solve the actual game, not the fake “pick a nice subsequence” version. The order of moves matters, but the whole thing collapses once you look at one target answer.
Threshold graph
Fix a number . We ask:
Can Alex force the final beauty to be at least ?
Create a graph with one vertex per array index. For every pair , add an edge if
If Alex locks both endpoints of any edge, the final beauty is at least . If he never locks both endpoints of an edge, the final beauty is less than .
So this is a vertex-claiming game:
Important: this is not absolute difference. The pair direction is index order. For , the value is . Turning this into is how you send your solution into the wall.
The key mini-game
First solve the version where Alex moves first on some graph.
If some vertex has degree at least , Alex wins immediately:
If every vertex has degree at most , then the graph is just a matching plus isolated vertices. Hao wins by a simple response strategy: whenever Alex locks one endpoint of an unmatched edge, Hao removes its partner. If Alex locks an isolated vertex, Hao removes anything. Alex never gets both endpoints of an edge.
Therefore, in an Alex-first game:
Back to the real game
In the real game, Hao moves first. Suppose Hao removes vertex . Then Alex is first on the remaining graph .
From the mini-game above:
So Alex can force beauty at least iff there is no vertex whose deletion makes all remaining degrees at most .
That gives a monotone predicate, so we binary search the largest winning .
Which first deletions can matter?
Let be the degree of vertex in , but we only care about values .
If all degrees are at most , Alex already loses the threshold game, so check(g)=false.
If some vertex has degree greater than 12$.
If the maximum degree is exactly , pick any vertex with degree . A successful first deletion must be either:
Otherwise still has degree after the deletion, and Alex wins.
So for each , we only test at most three candidate first moves by recomputing the capped degrees after deleting that candidate.
Computing capped degrees in linear time
Naively, has edges. We obviously do not build that unless we enjoy TLE as a lifestyle.
For a fixed right endpoint , dangerous left endpoints satisfy:
or equivalently:
We only need to know whether there are , , , or at least such endpoints. If there are at least three, the three smallest previous values will all work. If there are fewer than three, all working values are among the three smallest previous values anyway.
So scan left to right while maintaining the three smallest previous values. This counts dangerous partners to the left.
Similarly, for a fixed left endpoint j>i$ satisfy:
or:
Scan right to left while maintaining the three largest future values. This counts dangerous partners to the right.
Cap every count at . Exact degree is unnecessary; distinguishing from is enough.
Each degree computation is because the maintained lists have size at most three. Each check(g) recomputes this a constant number of times, so it is . Binary search gives:
per total input size, which is fine for .
Why the binary search works
If Alex can force beauty at least , then he can also force beauty at least any smaller value. Smaller only adds more edges to the threshold graph, never removes them.
So check(g) is monotone: true, true, true, then false, false, false as increases. The answer is the largest true .
Also, yes, the answer can be negative. The stock market got hands.
#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;
vector<ll> a(n);
for (ll &x : a) cin >> x;
auto measure = [&](ll g, int skip) {
vector<int> cnt(n, 0);
vector<ll> mn;
for (int i = 0; i < n; i++) {
if (i == skip) continue;
for (ll x : mn) {
if (a[i] - x >= g && cnt[i] < 3) cnt[i]++;
}
mn.push_back(a[i]);
sort(mn.begin(), mn.end());
if ((int)mn.size() > 3) mn.pop_back();
}
vector<ll> mx;
for (int i = n - 1; i >= 0; i--) {
if (i == skip) continue;
for (ll x : mx) {
if (x - a[i] >= g && cnt[i] < 3) cnt[i]++;
}
mx.push_back(a[i]);
sort(mx.rbegin(), mx.rend());
if ((int)mx.size() > 3) mx.pop_back();
}
return cnt;
};
auto canAlex = [&](ll g) {
vector<int> cnt = measure(g, -1);
int best = *max_element(cnt.begin(), cnt.end());
if (best <= 1) return false;
vector<int> candidates;
if (best > 2) {
for (int i = 0; i < n; i++) {
if (cnt[i] > 2) {
candidates.push_back(i);
break;
}
}
} else {
int v = -1;
for (int i = 0; i < n; i++) {
if (cnt[i] == 2) {
v = i;
break;
}
}
candidates.push_back(v);
for (int j = 0; j < n; j++) {
if (j == v) continue;
if (j < v && a[v] - a[j] >= g) candidates.push_back(j);
if (j > v && a[j] - a[v] >= g) candidates.push_back(j);
}
}
for (int p : candidates) {
vector<int> after = measure(g, p);
if (*max_element(after.begin(), after.end()) <= 1) return false;
}
return true;
};
ll lo = -1000000000LL, hi = 1000000000LL;
while (lo < hi) {
ll mid = lo + (hi - lo + 1) / 2;
if (canAlex(mid)) lo = mid;
else hi = mid - 1;
}
cout << lo << '\n';
}
}#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;
vector<ll> a(n);
for (ll &x : a) cin >> x;
auto measure = [&](ll g, int skip) {
vector<int> cnt(n, 0);
vector<ll> mn;
for (int i = 0; i < n; i++) {
if (i == skip) continue;
for (ll x : mn) {
if (a[i] - x >= g && cnt[i] < 3) cnt[i]++;
}
mn.push_back(a[i]);
sort(mn.begin(), mn.end());
if ((int)mn.size() > 3) mn.pop_back();
}
vector<ll> mx;
for (int i = n - 1; i >= 0; i--) {
if (i == skip) continue;
for (ll x : mx) {
if (x - a[i] >= g && cnt[i] < 3) cnt[i]++;
}
mx.push_back(a[i]);
sort(mx.rbegin(), mx.rend());
if ((int)mx.size() > 3) mx.pop_back();
}
return cnt;
};
auto canAlex = [&](ll g) {
vector<int> cnt = measure(g, -1);
int best = *max_element(cnt.begin(), cnt.end());
if (best <= 1) return false;
vector<int> candidates;
if (best > 2) {
for (int i = 0; i < n; i++) {
if (cnt[i] > 2) {
candidates.push_back(i);
break;
}
}
} else {
int v = -1;
for (int i = 0; i < n; i++) {
if (cnt[i] == 2) {
v = i;
break;
}
}
candidates.push_back(v);
for (int j = 0; j < n; j++) {
if (j == v) continue;
if (j < v && a[v] - a[j] >= g) candidates.push_back(j);
if (j > v && a[j] - a[v] >= g) candidates.push_back(j);
}
}
for (int p : candidates) {
vector<int> after = measure(g, p);
if (*max_element(after.begin(), after.end()) <= 1) return false;
}
return true;
};
ll lo = -1000000000LL, hi = 1000000000LL;
while (lo < hi) {
ll mid = lo + (hi - lo + 1) / 2;
if (canAlex(mid)) lo = mid;
else hi = mid - 1;
}
cout << lo << '\n';
}
}