Codeforces Round 944 (Div. 4) G(思維 + 位運算性質)

yanhy-orz發表於2024-09-11

題意

給定一個由 \(n\) 個非負整陣列成的陣列 \(a\)
如果 \(a_i \oplus a_j < 4\),那麼你就可以交換 \(a_i、a_j\),其中,\(\oplus\) 是按位異或。
求出操作若干次後,字典序最小的序列。

資料範圍:\(1 \le n \le 2 \times 10^5\)\(0 \le a_i \le 10^9\)

題解

性質:$ a_i \oplus a_j < 4 $ 的充分必要條件是:如果不考慮 \(a_i、a_j\) 二進位制下的最低兩位,那麼\(a_i、a_j\) 相等。

我們可以將 \(a_1 \sim a_n\) 劃分為若干個集合,每個集合內部實現升序排序,然後放回對應的位置。由於值域很大,因此這個操作可以用 std::map 實現。

時間複雜度為 \(\mathcal{O}(nlogn)\)


點選檢視程式碼
#include <bits/stdc++.h>

using i64 = int64_t;

inline int read() {
	bool sym = false; int res = 0; char ch = getchar();
	while (ch < '0' or ch > '9') sym |= (ch == '-'), ch = getchar();
	while (ch >= '0' and ch <= '9') res = (res << 3) + (res << 1) + (ch ^ 48), ch = getchar();
	return sym ? -res : res;
}

void solve() {
	int n = read();
	std::vector<int> a(n + 1);
	for (int i = 1; i <= n; i++) {
		a[i] = read();
	}
	
	std::map<int, std::priority_queue<int>> f;
	for (int i = 1; i <= n; i++) {
		f[a[i] ^ (a[i] & 3)].push(-a[i]);
	}
	for (int i = 1; i <= n; i++) {
		printf("%d%s", -f[a[i] ^ (a[i] & 3)].top(), i == n ? "\n" : " ");
		f[a[i] ^ (a[i] & 3)].pop();
	}
}

int main() {
	int T = read();
	while (T--) {
		solve();
	}
	return 0;
}

相關文章