[ARC127D] Sum of Min of Xor 题解
没有 \(\min\) 的情况是 trival 的,发现瓶颈在于如何比较两个数之间的大小。
可以发现,对两个二进制数,我们本质上是想要找到它们第一个不同的位置。于是考虑从最高位开始,将 \((a_i,b_i)\) 按最高位分组为 \((0,0),(0,1),(1,0),(1,1)\) 四组。每组内部需要继续枚举低位,因此只考虑两组之间的贡献。
可以发现,有贡献的组对如下:
- \((0,0),(0,1)\):此时贡献为 \(a_i\oplus a_j\)。
- \((0,0),(1,0)\):此时贡献为 \(b_i\oplus b_j\)。
- \((1,1),(0,1)\):此时贡献为 \(b_i\oplus b_j\)。
- \((1,1),(1,0)\):此时贡献为 \(a_i\oplus a_j\)。
- \((0,0),(1,1)\):贡献不确定,需要继续枚举,因此我们需要将这两组并在一起向下处理。
- \((0,1),(1,0)\):贡献不确定,需要继续枚举,因此我们需要将这两组并在一起向下处理。
直接爆算即可。
#include <iostream>
#include <vector>
using namespace std;
using LL = long long;
const int kN = 2.5e5 + 1;
const int kL = 18;
int n, a[kN], b[kN];
LL ans;
vector<int> sd;
void C(vector<int> &d1, vector<int> &d2, bool w) {
for (int i = 0; i < kL; ++i) {
int c11 = 0, c12 = 0;
for (int j : d1) {
c11 += (w ? b[j] : a[j]) >> i & 1;
}
for (int j : d2) {
c12 += (w ? b[j] : a[j]) >> i & 1;
}
ans += (1LL * c11 * (d2.size() - c12) + 1LL * (d1.size() - c11) * c12) << i;
}
}
void S(int p, vector<int> &d) {
if (d.empty()) {
return;
}
if (p == -1) {
for (int i = 0; i < kL; ++i) {
int c1 = 0;
for (int j : d) {
c1 += a[j] >> i & 1;
}
ans += 1LL * c1 * (d.size() - c1) << i;
}
return;
}
vector<int> l[2][2];
for (int i : d) {
l[a[i] >> p & 1][b[i] >> p & 1].push_back(i);
}
C(l[0][0], l[0][1], 0);
C(l[0][0], l[1][0], 1);
C(l[1][1], l[0][1], 1);
C(l[1][1], l[1][0], 0);
for (int i : l[1][1]) {
l[0][0].push_back(i);
}
for (int i : l[1][0]) {
l[0][1].push_back(i);
}
S(p - 1, l[0][0]), S(p - 1, l[0][1]);
}
int main() {
ios_base::sync_with_stdio(0), cin.tie(0);
cin >> n;
for (int i = 1; i <= n; ++i) {
cin >> a[i];
sd.push_back(i);
}
for (int i = 1; i <= n; ++i) {
cin >> b[i];
}
S(kL - 1, sd);
cout << ans;
return 0;
}

浙公网安备 33010602011771号