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.
Freeze one round and sort the active card values. Do not start with probability tricks; first understand Bob's payoff for fixed choices by Alice and Bob.
If Bob chooses a card to the right of Alice's card, then random cards left of Alice give 0 because Bob is farther, and random cards between them give 0 by the explicit between rule. Only cards strictly to Bob's right can score.
For a fixed Alice card , Bob's best right-side card is the immediate successor , and his best left-side card is the immediate predecessor . Moving farther away only makes the scoring tail worse.
So Alice minimizes , where and , with missing neighbors contributing .
is nondecreasing and is nonincreasing. Binary-search the first index with ; the optimum is there or one index before. Use Fenwick trees for dynamic order statistics and prefix sums.
Research note: I checked the Codeforces problem page and the official Educational Codeforces Round 187 editorial. The official page gives solution code instead of a full written proof; its core is exactly the two quantities usually named getL and getR, then a binary search over their crossing. The derivation below is original and uses the supplied statement as canonical.
Consider one fixed round with active cards, sorted as
The random card is chosen from the cards not selected by Alice or Bob, so it is useful to compute the total payoff over all possible random cards first, then divide by at the end.
Suppose Alice chooses and Bob chooses .
If , Bob's card is to the right of Alice's. For any random card , Bob is farther from than Alice, so the first zero condition triggers. For any , the card is between Alice and Bob, so the second zero condition triggers. The only cards that can pay are , and each contributes . Thus Bob's total payoff is
This gets worse as Bob moves farther right:
So among cards to the right of Alice, Bob should choose the immediate successor . Same story on the left, mirrored: if Bob chooses with , only cards can pay, giving
and increases as moves right. Therefore Bob's best left-side choice is the immediate predecessor .
So for Alice choosing , Bob's best total payoff is
where
and
For boundary cards, the missing side contributes . Alice wants
and the answer for the round is
No modulo nonsense while optimizing: compare the real integer totals first, then convert modulo .
Now we need find the minimum quickly after each insertion. The key shape is monotonic:
so is nondecreasing. Also
so is nonincreasing. Therefore decreases while dominates, then increases once dominates. The minimum is at the first index where , or at . That's the whole trick; everything else is data structures, not magic.
For dynamic prefixes, compress all values by order. Maintain:
For an active card at order position and compressed index id, compute:
id;prv[id];id;nxt[id].This gives and in . Binary-searching the crossing costs per round. With , that is comfortably fine. Values fit in long long because the worst relevant total is around .
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
const ll MOD = 998244353;
struct Fenwick {
int n;
vector<ll> bit;
Fenwick(int n = 0) : n(n), bit(n + 1, 0) {}
void add(int idx, ll val) {
for (++idx; idx <= n; idx += idx & -idx) bit[idx] += val;
}
ll sumPrefix(int idx) const {
if (idx < 0) return 0;
ll res = 0;
for (++idx; idx > 0; idx -= idx & -idx) res += bit[idx];
return res;
}
int kth(ll k) const {
int idx = 0;
int step = 1;
while ((step << 1) <= n) step <<= 1;
for (; step; step >>= 1) {
int nxt = idx + step;
if (nxt <= n && bit[nxt] < k) {
idx = nxt;
k -= bit[nxt];
}
}
return idx;
}
};
int main() {
setIO();
int m;
cin >> m;
vector<ll> a(m), xs;
for (ll &x : a) cin >> x;
xs = a;
sort(xs.begin(), xs.end());
vector<ll> inv(m + 1, 1);
for (int i = 2; i <= m; ++i) {
inv[i] = MOD - (MOD / i) * inv[MOD % i] % MOD;
}
Fenwick cnt(m), sum(m);
vector<int> prv(m, -1), nxt(m, -1);
set<int> active;
ll total = 0;
for (ll val : a) {
int id = lower_bound(xs.begin(), xs.end(), val) - xs.begin();
auto it = active.lower_bound(id);
int r = (it == active.end() ? -1 : *it);
int l = (it == active.begin() ? -1 : *prev(it));
prv[id] = l;
nxt[id] = r;
if (l != -1) nxt[l] = id;
if (r != -1) prv[r] = id;
active.insert(id);
cnt.add(id, 1);
sum.add(id, xs[id]);
total += xs[id];
int n = (int)active.size();
if (n < 3) continue;
auto cost = [&](int ord) -> pair<ll, ll> {
int v = cnt.kth(ord + 1);
ll leftCnt = ord;
ll leftSum = sum.sumPrefix(v - 1);
ll L = 0;
if (leftCnt > 0) L = xs[prv[v]] * leftCnt - leftSum;
ll rightCnt = n - ord - 1;
ll rightSum = total - sum.sumPrefix(v);
ll R = 0;
if (rightCnt > 0) R = rightSum - xs[nxt[v]] * rightCnt;
return {L, R};
};
int lo = 0, hi = n - 1, pos = n;
while (lo <= hi) {
int mid = (lo + hi) / 2;
auto [L, R] = cost(mid);
if (L >= R) {
pos = mid;
hi = mid - 1;
} else {
lo = mid + 1;
}
}
ll best = LLONG_MAX;
for (int ord : {pos, pos - 1}) {
if (0 <= ord && ord < n) {
auto [L, R] = cost(ord);
best = min(best, max(L, R));
}
}
cout << (best % MOD) * inv[n - 2] % MOD << '\n';
}
}#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
const ll MOD = 998244353;
struct Fenwick {
int n;
vector<ll> bit;
Fenwick(int n = 0) : n(n), bit(n + 1, 0) {}
void add(int idx, ll val) {
for (++idx; idx <= n; idx += idx & -idx) bit[idx] += val;
}
ll sumPrefix(int idx) const {
if (idx < 0) return 0;
ll res = 0;
for (++idx; idx > 0; idx -= idx & -idx) res += bit[idx];
return res;
}
int kth(ll k) const {
int idx = 0;
int step = 1;
while ((step << 1) <= n) step <<= 1;
for (; step; step >>= 1) {
int nxt = idx + step;
if (nxt <= n && bit[nxt] < k) {
idx = nxt;
k -= bit[nxt];
}
}
return idx;
}
};
int main() {
setIO();
int m;
cin >> m;
vector<ll> a(m), xs;
for (ll &x : a) cin >> x;
xs = a;
sort(xs.begin(), xs.end());
vector<ll> inv(m + 1, 1);
for (int i = 2; i <= m; ++i) {
inv[i] = MOD - (MOD / i) * inv[MOD % i] % MOD;
}
Fenwick cnt(m), sum(m);
vector<int> prv(m, -1), nxt(m, -1);
set<int> active;
ll total = 0;
for (ll val : a) {
int id = lower_bound(xs.begin(), xs.end(), val) - xs.begin();
auto it = active.lower_bound(id);
int r = (it == active.end() ? -1 : *it);
int l = (it == active.begin() ? -1 : *prev(it));
prv[id] = l;
nxt[id] = r;
if (l != -1) nxt[l] = id;
if (r != -1) prv[r] = id;
active.insert(id);
cnt.add(id, 1);
sum.add(id, xs[id]);
total += xs[id];
int n = (int)active.size();
if (n < 3) continue;
auto cost = [&](int ord) -> pair<ll, ll> {
int v = cnt.kth(ord + 1);
ll leftCnt = ord;
ll leftSum = sum.sumPrefix(v - 1);
ll L = 0;
if (leftCnt > 0) L = xs[prv[v]] * leftCnt - leftSum;
ll rightCnt = n - ord - 1;
ll rightSum = total - sum.sumPrefix(v);
ll R = 0;
if (rightCnt > 0) R = rightSum - xs[nxt[v]] * rightCnt;
return {L, R};
};
int lo = 0, hi = n - 1, pos = n;
while (lo <= hi) {
int mid = (lo + hi) / 2;
auto [L, R] = cost(mid);
if (L >= R) {
pos = mid;
hi = mid - 1;
} else {
lo = mid + 1;
}
}
ll best = LLONG_MAX;
for (int ord : {pos, pos - 1}) {
if (0 <= ord && ord < n) {
auto [L, R] = cost(ord);
best = min(best, max(L, R));
}
}
cout << (best % MOD) * inv[n - 2] % MOD << '\n';
}
}