本文最后更新于 8 个月前,文中所描述的信息可能已发生改变。
C. Serval and The Formula 解题思路
核心问题分析与数学转化
本题要求找到一个非负整数 ,使得:
位运算性质: 对于任意非负整数 ,都有 。
条件转化: 题目中的等式 等价于 。即:
这意味着 和 在二进制表示下,没有任何一位同时为 1。
1. 变量代换与简化
不妨设 (若 则交换)。 令 ,则 。 设差值 。
我们的目标转化为找到一个 (且 ),使得:
最后求出 。
特殊情况: 如果 ,则 ,条件变为 。但题目给定 ,且 ,因此 不可能为 0,故此时无解,输出 -1。
2. 构造策略 (利用进位消除)
我们要构造一个数 ,使得它和 没有公共的 1。 观察加法进位的特性:如果 的某一位是 1,且 的对应位也是 1,那么相加时该位会变成 0 并产生进位。
核心思路: 我们找到 的最高有效位 (MSB),设其位置为 (即 )。
- 构造 : 让 从第 位开始,一直到更高的位(比如第 40 位),全部置为 1。低于第 位的全部置为 0。
- 的形式:
...11111000...(最低的 1 在第 位)。 - 的形式:
...00001xxx...(最高的 1 在第 位)。
- 的形式:
- 验证 :
- 在第 位: 是 1, 也是 1。相加 ,结果位为 0,向 位进 1。
- 在第 位及以上: 依然是 1, 在这些位全是 0(因为 是 的最高位)。加上进位,,结果位为 0,继续向高位进 1。
- 结论: 这种连锁反应会使得 在所有 为 1 的位置上都变成了 0。而在 为 0 的低位上, 等于 ,两者自然没有交集。
3. C++ 代码实现细节
代码中使用 std::bitset 方便地处理二进制串。 需要注意的是 bitset::to_string() 生成的字符串,索引 0 对应的是最高位。
- 计算 。
- 将 转为 bitset 字符串,找到第一个 '1' 的位置(即最高位)。
- 构造 的字符串:从最高位开始直到 的最高位位置,全部填 '1'。
- 将构造的字符串转回
long long得到 。 - 输出 。
由于 的构造方式保证了其值远大于 ,且通常大于 ,所以计算出的 为非负数。
cpp
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
void solve() {
ll data_one, data_two;
cin >> data_one >> data_two;
// 保证 data_one <= data_two
if (data_one > data_two) {
swap(data_one, data_two);
} else if (data_one == data_two) {
// x = y 时,(x+k) & (x+k) = x+k,不为0(因x>=1),无解
cout << -1 << endl;
return;
}
ll target = data_two - data_one; // 差值 D
// 使用 bitset 处理二进制,大小 40 足够覆盖 10^9 和构造出的答案
bitset<40> bits_target(target);
string bits_target_string = bits_target.to_string();
// 初始化构造的 A 的 bitset,初始全 0
bitset<40> bits_ans(0);
string ans_string = bits_ans.to_string();
// 找到 target (D) 最高位的 1 在字符串中的下标
// 注意:to_string 后,下标 0 是最高位 (MSB)
size_t index_data = bits_target_string.find('1');
// 构造 A:将 A 的最高位到 D 的最高位对应位置全部置 1
// 逻辑上相当于构造了一个掩码:111...100...
if (index_data != string::npos) {
for (int i = 0; i <= index_data; i++) {
ans_string[i] = '1';
}
}
// 将构造的二进制字符串转回数值 A,计算 k = A - x
ll ans_val = stoll(ans_string, nullptr, 2);
ll k = ans_val - data_one;
cout << k << endl;
}
int main() {
ios_base::sync_with_stdio(false);
cin.tie(nullptr);
int t;
cin >> t;
while (t--) {
solve();
}
}