【位运算】codeforces 1775 C. Interesting Sequence
题意
输入一个正整数 \(T(1 \leq T \leq 2000)\),代表 \(T\) 组测试用例。对于每个测试用例:
输入两个整数 \(n, m(0 \leq n, m \leq 10^{18})\),问:能否找到一个数 \(n + x\) 使得 \(n\) & \((n + 1)\) & ... & \((n + x) == m\) 成立?若能,输出最小的 \(n + x\),否则输出 \(-1\)。
题解
对于 \(n \lt m\) 的情况,由于与运算只会使结果单调不增,因此 \(n \lt m\) 的情况必定无法找到合适的解。
对于 \(n == m\) 的情况,明显直接输出 \(n\) 即可。
对于 \(m \lt n\) 的情况,首先必须保证 \(n\) & \(m == m\),否则必定无法找到合适的解。比如:\(6_{10}(1100_2)\) 和 \(2_{10}(0010_2)\),由于 \(6_{10}\) 的第 \(2\) 位bit是 \(0\),那么这一个bit位进行与运算的结果必定为 \(0\),必不成立。对于 \(n\) & \(m = m\) 成立的情况,可对 \(m == 0\) 是否成立进行讨论:
- \(m == 0\) 成立,只需要找到一个能使 \(n\) 在二进制形式下全部位数都置为 \(0\) 的数即可,明显最小的符合要求的数就是 \(n\) 在二进制形式下最高位的 \(1\) 再左移一位的结果。比如:\(13_{10}(01101_2)\) & \(16_{10}(10000_2) == 0\)。
- \(m == 0\) 不成立,假设当前的值为 \(n\),那么必须先与 \(n + 1\) 进行与运算,那么可得知的是二进制形式下必定是低位先被置为 \(0\),并且在进行位运算的时候,不可以使得 \(n\) & \(m == m\) 不再成立。所以只需要先算出 \(m\) 的最低位的 \(1\) 的位置 \(lb\),再判断出当 \(lb > 1\) 时 \(n\) 的 \(lb - 1\) 位是否为 \(1\) 即可,若是必定无解,否则答案就是 \(n\) 再异或上第一段从 \(lb - 1\) 起至最低位连续的 \(1\)的结果。
参考代码
#include<bits/stdc++.h>
#define IOS ios::sync_with_stdio(false);cin.tie(nullptr);cout.tie(nullptr);
using namespace std;
typedef long long ll;
ll ans, n, m;
int T = 1;
void solve() {
cin >> n >> m;
if (n < m || n & m != m) ans = -1;
else if (n == m) ans = n;
else {
int t = __builtin_ffsll(m);
if (!m) {
for (int i = 61; i >= 0; -- i) {
if (n >> i & 1) {
ans = 1LL << (i + 1);
break;
}
}
} else if (n >> t != m >> t || t > 1 && n >> t - 2 & 1) ans = -1;
else {
for (int i = t - 3; i >= 0; -- i) {
if (n >> i & 1) {
ans = 1LL << i + 1 | n >> t - 1 << t - 1;
while (i >= 0 && n >> i & 1) {
ans &= ~(1LL << i);
-- i;
}
break;
}
}
}
}
cout << ans << '\n';
}
int main() {
IOS
cin >> T;
while (T --) solve();
return 0;
}