CF1322B Present
给定 \(n\) 个数 \(a_{1 \sim n}\),求 \(\oplus_{i = 1}^{n - 1} \oplus_{j = i + 1}^{n} (a_i + a_j)\)。
考虑经典的按位操作。假设我们现在想求答案的第 \(k\) 位(二进制下,下同),我们可以取出所有数的前 \(k\) 位,模拟一下不难理解,有贡献的 \(a_i + a_j \in[2^i,2^{i + 1} - 1] \cup [3 \times 2 ^ i, 4 \times 2 ^ {i} - 2]\)(指分别取出前 \(k\) 位再相加的结果),其中 \(4 \times 2 ^ i - 2\) 不是什么深奥的东西,就是两个 \(k\) 位数和的最大值。
并集的两个范围分别是经典的双指针处理(当然也可以二分,但时间复杂度没那么好),最后有 奇数个 数对 在范围中意味着答案的第 \(k\) 位是 \(1\)。时间复杂度 \(O(24n \log_{n} )\)。\(24\) 是值域的对数。
#include<bits/stdc++.h>
#define F(i,l,r) for(int i(l); i <= (r); ++ i)
#define G(i,r,l) for(int i(r); i >= (l); -- i)
#define ll long long
using namespace std;
const int N = 4e5 + 5;
int a[N], b[N], n, ans = 0;
bool calc(int L, int R){int sm = 0;for(int i = n, l = 1, r = 1; i; -- i){while(l <= n && b[i] + b[l] < L) ++ l;while(r <= n && b[i] + b[r] <= R) ++ r;sm += r - l - (l <= i && r > i);}return (sm >> 1) & 1;
}
bool check(int bit){int p = 1 << (bit + 1);F(i, 1, n) b[i] = a[i] % p;sort(b + 1, b + n + 1);return calc(1 << bit, (1 << (bit + 1)) - 1) ^ calc(3 << bit, (1 << (bit + 2)) - 2);
}
signed main() {ios::sync_with_stdio(0); cin.tie(0); cout.tie(0);cin >> n;F(i, 1, n) cin >> a[i];F(i, 0, 24) if(check(i)) ans = ans ^ (1 << i);cout << ans << '\n';return fflush(0), 0;
}
本题做过之后一定要强化记忆这个双指针操作和它的模板。