C. Interesting Sequence
Petya and his friend, robot Petya++, like to solve exciting math problems.
One day Petya++ came up with the numbers $n$ and $x$ and wrote the following equality on the board: $$n\ \&\ (n+1)\ \&\ \dots\ \&\ m = x,$$ where $\&$ denotes the bitwise AND operation. Then he suggested his friend Petya find such a minimal $m$ ($m \ge n$) that the equality on the board holds.
Unfortunately, Petya couldn't solve this problem in his head and decided to ask for computer help. He quickly wrote a program and found the answer.
Can you solve this difficult problem?
Input
Each test contains multiple test cases. The first line contains the number of test cases $t$ ($1 \le t \le 2000$). The description of the test cases follows.
The only line of each test case contains two integers $n$, $x$ ($0\le n, x \le 10^{18}$).
Output
For every test case, output the smallest possible value of $m$ such that equality holds.
If the equality does not hold for any $m$, print $-1$ instead.
We can show that if the required $m$ exists, it does not exceed $5 \cdot 10^{18}$.
Example
input
5 10 8 10 10 10 42 20 16 1000000000000000000 0
output
12 10 -1 24 1152921504606846976
Note
In the first example, $10\ \&\ 11 = 10$, but $10\ \&\ 11\ \&\ 12 = 8$, so the answer is $12$.
In the second example, $10 = 10$, so the answer is $10$.
In the third example, we can see that the required $m$ does not exist, so we have to print $-1$.
解题思路
首先遍历$n$和$x$在二进制下的每一位,用$n_k$来表示数字$n$二进制的第$k$位的数值,当遍历到第$k$位时发现$n_k = 0$,$x_k = 1$,那么就必定无解。因为整个过程都是按位与的运算,如果$n_k = 0$,那么无论与什么数相与得到的结果都是$0$而不可能得到$1$。
接下来分类讨论:
- $n_k = 0$,$x_k = 0$。那么$m$可以取任何数,最终$n_k\ \&\ (n+1)_k\ \& \ \dots\ \&\ m_k = x_k = 0$总是成立。
- $n_k = 1$,$x_k = 0$。为了按位与后第$k$位为$0$,那么很明显应该让$n$加上某个数$s$后$(n+s)_{k} = 0$,这样才能有$n_k\ \&\ (n+1)_k\ \&\ \dots\ (n+s)_k\ \&\ \dots\ \&\ m_k = x_k = 0$。很显然为了让$n+s$的第$k$位出现$0$,$s$可以取到无穷大,因此我们来看看$s$最小可以取到多少。可以发现$n$的第$k$位要进位时才由变$1$变$0$,因此只用考虑由$n$的前$k$位所构成的数,即$n\ \%\ {2^{k+1}}$,第$k$位进位后得到的结果为$2^{k+1}$,因此$s$的最小值为$2^{k+1} - n\ \%\ {2^{k+1}}$。
- $n_k = 1$,$x_k = 1$。为了按位与后第$k$位始终为$1$,那么在$n \sim m$的数中不能出现第$k$位为$0$的数。一样的,当$n$的第$k$位要进位时才由变$1$变$0$,考虑由$n$的前$k$位所构成的数,即$n\ \%\ {2^{k+1}}$,那么在进位前且第$k$位仍为$1$所能取到的最大值是$2^{k+1}-1$,因此$s$的取值不应超过$2^{k+1}-1 - n\ \%\ {2^{k+1}}$。
然后对第$2$种情况的所有$s$取个最大值(即找到最大的下界)得到$l$,对第$3$种情况的所有$s$取个最小值(即找到最小的上界)得到$r$。如果$l \leq r$说明有解,那么答案就是$m = n + l$;否则就是无解。
AC代码如下:
1 #include <bits/stdc++.h> 2 using namespace std; 3 4 typedef long long LL; 5 6 void solve() { 7 LL n, m; 8 scanf("%lld %lld", &n, &m); 9 LL l = 0, r = 9e18; 10 for (int i = 0; i < 60; i++) { // 1e18的二进制位最多有60位 11 LL x = n % (1ll << i + 1); // 得到n的前i位所构成的数 12 int a = n >> i & 1, b = m >> i & 1; 13 if (!a && b) { // n的第k位为0,m的第k位为1,无解 14 printf("-1\n"); 15 return; 16 } 17 if (a && !b) l = max(l, (1ll << i + 1) - x); // 第一种情况 18 else if (a && b) r = min(r, (1ll << i + 1) - 1 - x); // 第二种情况 19 } 20 printf("%lld\n", l <= r ? n + l : -1); 21 } 22 23 int main() { 24 int t; 25 scanf("%d", &t); 26 while (t--) { 27 solve(); 28 } 29 30 return 0; 31 }
参考资料
Codeforces Round #843 (Div. 2) C (思维):https://zhuanlan.zhihu.com/p/598221402
标签:dots,10,le,equality,Sequence,Interesting,Petya,test From: https://www.cnblogs.com/onlyblues/p/17057484.html