[Codeforces 1323D] Present
https://codeforces.com/contest/1323/problem/D
题意:
求 \(a\) 序列中所有无序对 \(x, y\) \((x \lt y)\) 和(即 \(a_x + a_y\) )的异或和。
思路:
位运算考虑拆位思考。设当前二进制位为第 \(k\) 位,如果第 \(k\) 位有贡献当且仅当有奇数个 \(1\) 。考虑如何快速计算 \(1\) 的数量。两数做加法后,第 \(k\) 位仅受到 前 \(k\) 位影响。所以我们从高到低,每次仅保留 \(0\) ~ \(k\) 位,发现对于给定的 \(a_x\) 和 \(a_y\),需要满足 \(a_x + a_y\) \(\in\) \([2^k, 2^{k + 1} - 1]\) \(\bigvee\) \([2^{k + 1} + 2^k, 2^{k + 2} - 1]\) 。我们可以每次处理完 \(a\) 后对其排序,确定 \(x\) 后找 \(y\) 的数量,得到一个时间复杂度 \(O(nlog^2n)\) 的可通过的程序。
进一步考虑性质。因为 \(a\) 有序了,所以如果有序取 \(x\) ,那么 \(y\) 的区间范围也是单调的。而对 \(a\) 排序可以将上一次的 \(a\) 分成两个有序序列,做一个归并排序。由此我们得到了时间复杂度 \(O(nlogn)\) 的优秀程序。
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const ll INF = 0x3f3f3f3f3f3f3f3f;
void solve() {
int n;
cin >> n;
vector<int> a(n);
for (int i = 0; i < n; ++i) cin >> a[i];
sort(a.begin(), a.end());
int ans = 0;
for (int k = 25; k >= 0; --k) {
vector<int> A, B;
for (int i = n - 1; i >= 0; --i) {
if (a[i] >> (k + 1) & 1) {
A.emplace_back(a[i]);
}
else B.emplace_back(a[i]);
}
a.clear();
for (auto &u : A) {
u ^= (1 << (k + 1));
}
while (!A.empty() || !B.empty()) {
if (A.empty()) {
a.emplace_back(B.back());
B.pop_back();
} else if (B.empty()) {
a.emplace_back(A.back());
A.pop_back();
} else if (A.back() < B.back()) {
a.emplace_back(A.back());
A.pop_back();
} else {
a.emplace_back(B.back());
B.pop_back();
}
}
int num = 0;
int head1 = n, head2 = n, rear1 = n, rear2 = n;
for (int i = 0; i < n; ++i) {
while (head1 > i && a[head1 - 1] >= (1 << k) - a[i]) head1--;
while (rear1 > i && a[rear1 - 1] > (1 << (k + 1)) - 1 - a[i]) rear1--;
if (head1 <= i) head1 = i + 1;
if (rear1 > i) num += rear1 - head1;
while (head2 > i && a[head2 - 1] >= (1 << (k + 1)) + (1 << k) - a[i]) head2--;
while (rear2 > i && a[rear2 - 1] > (1 << (k + 2)) - 1 - a[i]) rear2--;
if (head2 <= i) head2 = i + 1;
if (rear2 > i) num += rear2 - head2;
}
if (num & 1) ans += 1 << k;
}
cout << ans << '\n';
}
int main() {
#ifndef stff577
ios::sync_with_stdio(false);
cin.tie(nullptr);cout.tie(nullptr);
cout << fixed << setprecision(20);
#endif
int t = 1;
while (t--) solve();
return 0;
}