桁ごとに考えるしかなさそうなのはそれはそう...
問題概要 (ARC 092 D / ABC 091 D)
要素の数列 と が与えられる。 個の整数 の XOR 和を求めよ。
制約
- <
解法
XOR 和と言われた時点で、各桁ごとにカウントしたい気持ちにはなる。 個の整数のうち、 桁目のビットが立っているやつが何個あるかを数えればよい。
に対して、, , ..., のうちの何個について、 桁目にビットが立っているかを求めることを考える。
ここで
の 桁目の値が 1
⇔ () の値が 以上 未満
で、これは , に対して をあらかじめとっておいたとき、
- のとき、 <
- そうでないとき、 < または <
と同値である。こうして、これを満たす の個数は予め をソートしておいて二分探索などで求めることができる。
全体の計算量は 。
#include <iostream> #include <vector> #include <algorithm> using namespace std; int N; vector<int> a, b; int main() { cin >> N; a.resize(N); for (int i = 0; i < N; ++i) cin >> a[i]; b.resize(N); for (int i = 0; i < N; ++i) cin >> b[i]; int res = 0; for (int digit = 29; digit >= 0; --digit) { int bekihigh = 1<<(digit+1), bekilow = 1<<digit; for (int i = 0; i < N; ++i) a[i] %= bekihigh, b[i] %= bekihigh; sort(b.begin(), b.end()); long long num = 0; for (int i = 0; i < N; ++i) { int add = 0; if (bekilow - a[i] >= 0) { add += lower_bound(b.begin(), b.end(), bekihigh-a[i]) - lower_bound(b.begin(), b.end(), bekilow-a[i]); } else { add += lower_bound(b.begin(), b.end(), bekihigh-a[i]) - b.begin(); add += lower_bound(b.begin(), b.end(), bekihigh) - lower_bound(b.begin(), b.end(), bekihigh + bekilow - a[i]); } num += add; } if (num & 1) res += bekilow; } cout << res << endl; }