Official

G - Max of Medians Editorial by en_translator


We do binary search for the answer.

We define functions \(f\), \(g\), \(f_d\), and \(g_d\) as follows:

  • Let \(f(C,x)\) be the maximum \(k\) such that we can rearrange the sequence \(C\) to make all of \(C_1 \oplus C_2, C_3 \oplus C_4, \ldots, C_{2k-1} \oplus C_{2k}\) greater than or equal to \(x\).

  • Let \(g(C,D,x)\) be the maximum \(k\) such that we can rearrange the sequences \(C\) and \(D\) to make all of \(C_1 \oplus D_1, C_2 \oplus D_2, \ldots, C_k \oplus D_k\) greater than or equal to \(k\).

  • Let \(f_d(C,x) \coloneqq f(C',x')\), where \(C'\) is the sequence obtained by replacing each element \(i\) of \(C\) with \(i \bmod 2^{d+1}\), and \(x' \coloneqq x \bmod 2^{d+1}\).

  • Let \(g_d(C,D,x) \coloneqq g(C', D', x')\), where \(C'\) is the sequence obtained by replacing each element \(i\) of \(C\) with \(i \bmod 2^{d+1}\), \(D'\) by replacing each element \(i\) of \(D\) with \(i \bmod 2^{d+1}\), and \(x' \coloneqq x \bmod 2^{d+1}\).

Intuitively, \(f_d\) and \(g_d\) care only about \(2^{d+1}\)s and greater places.

It is sufficient to determine if \(f(A,x) \geq \lfloor \frac{N+1}{2} \rfloor\).

Since \(f(A,x) = f_{29}(A,x)\), we seek for \( f_{29}(A,x)\).

In fact, the values of \(f_d(C,x)\) and \(g_d(C,D,x)\) can be found recursively from the values of \(f_{d-1}\) and \(g_{d-1}\) at several points. We will describe this recursion in detail. For a sequence \(X\), we denote by \(|X|\) its length.

1. Finding \(f_d(C,x)\)

For simplicity, we assume that \(x\) and each element of \(C\) is between \(0\) (inclusive) and \(2^{d+1}\) (exclusive).

For \(d \geq 0\), let \(C^{(0)}\) and \(C^{(1)}\) be the sequences consisting of the elements of \(C\) whose \(2^d\) places are \(0\) and \(1\), respectively.

1-1. if \(d = -1\)

\(f_d(C,x) = \lfloor \frac{|C|}{2} \rfloor\) (which is the base case of the recursion).

1-2. if \(d \geq 0\) and the \(2^d\)s place of \(x\) is \(0\)

By symmetry, we can assume that \(|C^{(0)}| \leq |C^{(1)}|\). The XOR of an element of \(C^{(0)}\) and another of \(C^{(1)}\) is always \(2^d\) or greater; since \(2^d > x\), it is also \(x\) or greater. Thus, \(f_d(C,x) = |C^{(0)}| + \min (\lfloor \frac {(|C^{(1)}| - |C^{(0)}|)}{2} \rfloor, f_{d-1}(C^{(1)}, x)\). (This is valid because we can pair an element of \(C^{(0)}\) and another of \(C^{(1)}\) greedily).

1-3. if \(d \geq 0\) and the \(2^d\)s place of \(x\) is \(1\)

The XOR of an element of \(C^{(0)}\) and another of \(C^{(1)}\) is always strictly less than \(2^d\); since \(2^d \leq x\), it is also strictly less than \(x\). Thus, \(f_d(C,x) = g_{d-1}(C^{(0)}, C^{(1)}, x)\).

2. Finding \(g_d(C,D,x)\)

It can be found in almost the same way as \(f_d(C,D,x)\).

For simplicity, we assume that \(x\) and each element of \(C\) and \(D\) is between \(0\) (inclusive) and \(2^{d+1}\) (exclusive).

For \(d \geq 0\), let \(C^{(0)}\) and \(C^{(1)}\) be the sequences consisting of the elements of \(C\) whose \(2^d\) places are \(0\) and \(1\), respectively; let \(D^{(0)}\) and \(D^{(1)}\) be the sequences consisting of the elements of \(D\) whose \(2^d\) places are \(0\) and \(1\), respectively.

2-1. if \(d=-1\)

\(g_d(C,D,x) = \min(|C|,|D|)\) (which is the base case of the recursion).

2-2. if \(d \geq 0\) and the \(2^d\)s place of \(x\) is \(0\)

By symmetry, we can assume that \(|C^{(0)}| \leq |D^{(1)}|\). The XOR of an element of \(C^{(0)}\) and another of \(D^{(1)}\), and the XOR of an element of \(C^{(1)}\) and another of \(D^{(0)}\), is always \(2^d\) or greater; by \(2^d > x\), it is also \(x\) or greater.

2-2-1. if \(|C^{(1)}| \leq |D^{(0)}|\)

\(g_d(C,D,x) = |C^{(0)}| + |C^{(1)}|\) (which can be easily evaluated from lower and upper).

2-2-2. if \(|C^{(1)}| > |D^{(0)}|\)

\(g_d(C,D,x) = |C^{(0)}| + |D^{(0)}| + \min(|C^{(1)}| - |D^{(0)}|, |D^{(1)}| - |C^{(0)}|, g_{d-1}(C^{(1)}, D^{(1)}, x))\). (This is true because we can greedily pair an element of \(C^{(0)}\) and another of \(D^{(1)}\), and an element of \(D^{(0)}\) and another of \(C^{(1)}\).)

2-3. if \(d \geq 0\) and the \(2^d\)s place of \(x\) is \(1\)

The XOR of an element of \(C^{(0)}\) and another of \(D^{(1)}\), and the XOR of an element of \(C^{(1)}\) and another of \(D^{(0)}\), is always strictly less than \(2^d\); by \(2^d \leq x\), it is also strictly less than \(x\). Thus, \(g_d(C,D,x) = g_{d-1}(C^{(0)}, D^{(1)}, x) + g_{d-1}(C^{(1)}, D^{(0)}, x)\).


Hence, the sought value is found by computing this recursion. For each \(d\), we evaluate \(O(N)\) points, so the decision problem is solved in an \(O(N \log \max A_i)\) time, and the entire problem is solved in a total of \(O(N (\log \max A_i) ^ 2)\) time. Observing the recursion equation, we can actually see that \(f(A,x) = \lfloor \frac {g(A,A,x)}{2} \rfloor\), so the answer can be found without using \(f\) and \(f_d\).

The following is a sample code. Note that the variable names may differ from the editorial, and in the recursion, instead of explicitly taking a sequence, we sort \(A\) and receive it in the form of \(A[l:r]\). To find the appropriate \(m\) to divide \(C = A[l:r]\) into \(|C^{(0)}| = A[l:m]\) and \(|C^{(1)}| = A[m:r]\), a precalculation using the sliding window trick is performed (but we have confirmed that we can always do a binary search in every recursion).

#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;

const int N = 200010;
vector<vector<int>> v(30, vector<int>(N));

int g(vector<int> &a, int xl, int xr, int yl, int yr, int x, int d) {
	if (xl == xr || yl == yr) return 0;
	if (d == -1) return min(xr - xl, yr - yl);
	int xm = v[d][xl], ym = v[d][yl];
	int x1 = xm - xl, x2 = xr - xm, y1 = ym - yl, y2 = yr - ym;
	if (x >> d & 1) {
		int c1 = g(a, xl, xm, ym, yr, x, d - 1);
		int c2 = g(a, xm, xr, yl, ym, x, d - 1);
		return c1 + c2;
	}
	else {
		bool f1 = x1 <= y2;
		bool f2 = x2 <= y1;
		if (f1 && f2) return x1 + x2;
		else if (!f1 && !f2) return y1 + y2;
		else if (f1 && !f2) {
			int r = min({ g(a, xm, xr, ym, yr, x, d - 1), y2 - x1, x2 - y1 });
			return r + x1 + y1;
		}
		else if (!f1 && f2) {
			int r = min({ g(a, xl, xm, yl, ym, x, d - 1), x1 - y2, y1 - x2 });
			return r + x2 + y2;
		}
	}
}

int f(vector<int> &a, int l, int r, int x, int d) {
	if (l == r) return 0;
	if (d == -1) return (r - l) / 2;
	int m = v[d][l];
	int x1 = m - l, x2 = r - m;
	if (x >> d & 1) return g(a, l, m, m, r, x, d - 1);
	else {
		if (x1 <= x2) return min((x2 - x1) / 2, f(a, m, r, x, d - 1)) + x1;
		else return min((x1 - x2) / 2, f(a, l, m, x, d - 1)) + x2;
	}
}

int main() {
	int n;
	cin >> n;
	vector<int> a(2 * n);
	for (int i = 0; i < 2 * n; i++) cin >> a[i];
	sort(a.begin(), a.end());
	a.push_back(7 << 28);
	int ans = 0;
	for (int i = 0; i < 30; i++) {
		int f = 0;
		int z = 1 << (i + 1);
		int nxt = a[0] / z * z + z / 2;
		int mx = a[0] / z * z + z;
		int tmp = -1;
		for (int j = 0; j < 2 * n + 1; j++) {
			if (a[j] >= nxt && tmp == -1) tmp = j;
			if (a[j] >= mx) {
				for (int k = f; k < j; k++) v[i][k] = tmp;
				f = j;
				nxt = a[j] / z * z + z / 2;
				mx = a[j] / z * z + z / 2;
				tmp = -1;
			}
			if (a[j] >= nxt && tmp == -1) tmp = j;
		}
	}
	for (int b = 29; b >= 0; b--) {
		int tmp = ans | (1 << b);
		int cnt = f(a, 0, 2 * n, tmp, 29);
		if (cnt >= (n + 1) / 2) ans |= 1 << b;
	}
	cout << ans << '\n';
}

posted:
last update: