题解:CF2267F2 XOR Transformations (Hard Version)

什么叫 F1 被卡常了一怒之下写了 F2?

典完了。

猜测操作次数不能太多。不妨设当前所有数都 \(<2^k\),其中有 \(x\) 个数在第 \(k-1\) 位上为 \(1\),\(n-x\) 个数在第 \(k-1\) 位上为 \(0\),那么只有 \(\dbinom{x}{2}+\dbinom{n-x}{2}\) 个数对的异或和 \(<2^{k-1}\)。取 \(x=\left\lfloor\dfrac{n}{2}\right\rfloor\) 时上式取到最小值,而对于 \(n\geq 5\),不难证明 \(\dbinom{\lfloor n/2\rfloor}{2}+\dbinom{\lceil n/2\rceil}{2}\geq n-1\)。又因为 \(\dbinom{n-1}{2}\geq n\),所以至多 \(2\) 次操作后所有数 \(<2^{k-1}\)。因此最多操作 \(2\lceil\log V\rceil\) 次。

现在问题只剩下如何快速求出 \(a_i\oplus a_j\) 的前 \(n\) 小值。把 \(a\) 扔到 Trie 上,容易做到 \(\mathcal{O}(\log{V})\) 求 \(a_i\oplus v\) 的第 \(k\) 小值 \(\operatorname{kth}(v,k)\)。为了排除 \(a_i\oplus a_i\) 的情况,这里要钦定 \(k\geq 2\)。然后直接多路归并,用一个小根堆维护所有 \((\operatorname{kth}(a_i,k),a_i,k)\),每次取出堆顶令 \(k\gets k+1\) 再塞回去。注意这里一个无序对会被考虑两次,我们直接求出前 \(2n\) 小值,取偶数位置上的数放到 \(a\) 里即可。

时间复杂度为 \(\mathcal{O}(n\log{n}\log{V}+n\log^2{V})\)。

代码
#include <bits/stdc++.h>

using namespace std;

using ll = long long;
using i128 = __int128;
using ui = unsigned int;
using ull = unsigned long long;
using u128 = unsigned __int128;
using ld = long double;
using pii = pair<int, int>;
const int MAXN = 1e5 + 5;

template<typename T> T lowbit(T x) { return x & -x; }
template<typename T> void chkMin(T &x, T y) { x = y < x ? y : x; }
template<typename T> void chkMax(T &x, T y) { x = x < y ? y : x; }
constexpr int lg2(ll x) { return 63 ^ __builtin_clzll(x); }
constexpr ll bitCeil(ll x) { return x == 1 ? 1ll : 1ll << lg2(x - 1) + 1; }

int tc, n, q, a[MAXN], tmp[MAXN];

struct Trie {
	static const int MAXC = 3e6 + 5;
	int tot, son[MAXC][2], cnt[MAXC];

	void init() {
		for (int i = 0; i <= tot; ++i) son[i][0] = son[i][1] = cnt[i] = 0;
		tot = 0;
	}

	void ins(int x) {
		int p = 0;
		for (int i = 29; i >= 0; --i) {
			int ch = x >> i & 1;
			if (!son[p][ch]) son[p][ch] = ++tot;
			++cnt[p = son[p][ch]];
		}
	}

	int kth(int x, int k) {
		int p = 0, res = 0;
		for (int i = 29; i >= 0; --i) {
			int ch = x >> i & 1, q = son[p][ch];
			if (k <= cnt[q]) {
				p = q;
			} else {
				k -= cnt[q];
				res |= 1 << i;
				p = son[p][ch ^ 1];
			}
		}
		return res;
	}
} T;

int main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
	
	cin >> tc;
	while (tc--) {
		cin >> n >> q;
		for (int i = 1; i <= n; ++i) cin >> a[i];

		vector<int> ans;
		while (true) {
			int mx = *max_element(a + 1, a + n + 1), mn = *min_element(a + 1, a + n + 1);
			if (!mx) break;
			ans.emplace_back(mx - mn);

			T.init();
			for (int i = 1; i <= n; ++i) T.ins(a[i]);

			priority_queue<tuple<int, int, int>, vector<tuple<int, int, int>>, greater<>> Q;
			for (int i = 1; i <= n; ++i) Q.emplace(T.kth(a[i], 2), i, 2);
			for (int i = 1; i <= n * 2; ++i) {
				auto [val, id, k] = Q.top();
				Q.pop();
				if (~i & 1) tmp[i >> 1] = val;
				if (k < n && i < n * 2) Q.emplace(T.kth(a[id], k + 1), id, k + 1);
			}
			copy(tmp + 1, tmp + n + 1, a + 1);
		}

		while (q--) {
			int x;
			cin >> x;
			cout << (x < ans.size() ? ans[x] : 0) << '\n';
		}
	}
	return 0;
}
posted @ 2026-09-26 11:09  P2441M  阅读(3)  评论(0)    收藏  举报