#位运算 ## 题目大意 给定 $a,b$ 和 $C$,现在要你找到两个正整数 $x$ 和 $y$,使得 $x$ 的对应二进制数当中 $1$ 的个数为 $a$,$y$ 的对应二进制当中 $1$ 的个数为 $b$,以及 $x\oplus y=C$。 ## 解法 首先,我们知道 $x\oplus 0=x$ 和 $x\oplus x=0$,然后考虑构造方案。不如先令 $x=C,y=0$,那么很显然 $x\oplus y=C$。接下来考虑如何满足条件一二,我们可以将 $x$ 的一些位置上面的 $1$ 移动到 $y$ 上面,这样子 $x\oplus y$ 仍等于 $C$。但是有可能位数不够用,这时候我们就需要找到一些 $x$ 和 $y$ 都等于 $0$ 的位置,然后把这个位置上面的数都改成 $1$,这样子 $x\oplus y$ 也是等于 $C$ 的。 为了让他们尽量匹配,在把 $x$ 的 $1$ 移到 $y$ 身上的时候,我们需要尽量的匀称,简单来说就是让 $a-\text{popcount(x)}$ 尽量接近 $b-\text{popcount}(y)$。 具体操作请看代码。 ## 代码 ```cpp #include <iostream> #include <bitset> using namespace std; using LL = unsigned long long; const LL kMaxN = 2e5 + 5; LL a, b, c; bitset<60> x, y; int main() { cin >> a >> b >> c; x = c; // 先令 x = c LL cnt = 0, res = (x.count() + b - a) / 2; // 计算需要移多少个 for (LL i = 0; cnt < res && i < 60; i++) { // 移动 res 次 if (x[i]) { // 如果可以移 x[i] = 0, y[i] = 1; // 移过去 cnt++; // 计数器累加 } } cnt = 0, res = a - x.count(); // 清空并计算要填多少个 1 for (LL i = 0; cnt < res && i < 60; i++) { // 填 1 if (!x[i] && !y[i]) { // 找空的地方填 x[i] = y[i] = 1; // 填上去 cnt++; // 计数器累加 } } if (x.count() != a || y.count() != b || (x.to_ullong() ^ y.to_ullong()) != c) { cout << "-1\n"; } else { cout << x.to_ullong() << ' ' << y.to_ullong() << '\n'; } return 0; } ```