您的位置:首页 > 其它

或与加问题

2016-12-13 22:10 225 查看
题目:

给定 x, k ,求满足 x + y = x | y 的第 k 小的正整数 y 。 | 是二进制的或(or)运算,例如 3 | 5 = 7。

比如当 x=5,k=1时返回 2,因为5+1=6 不等于 5|1=5,而 5+2=7 等于 5 | 2 = 7。

代码:

#include <iostream>

using namespace std;

int main()
{
long long x, k;
cin>>x>>k;
long long bitNum = 1;
long long ans = 0;
while(k)
{
if((x & bitNum) == 0)
{
ans += (bitNum * (k & 1));
k >>= 1;
}
bitNum <<= 1;
}
cout<<ans<<endl;
return 0;
}

思路:

应该没有更简单的解法了

-----解法说明------

x+y=x|y

这里可以推出一个结论,x&y=0。也就是说,在二进制上看,x取1的地方,y必定不能取1。从最低位考虑,若x与y在某一位上同时取1,则x+y在该位上为0,x|y在该位上为1,前面说这是最低一位x y同时取1,也就是说没有更低位加法的进位,所以这里两个结果不相等,出现了矛盾。

例子:

x = 001010

y = 110110

x + y =  1000000

x | y = 111110

偏差产生的原因是倒数第二位,x+y=0 x|y=1 且倒数第一位加法没有进位

结论:x在二进制取1的位上,y不能做出改变,只能取0

----方法----

有了上述结论,可以进一步推出只要在x取0的地方,y可以做出改变

例如

x = 10010010011

y = 00000000(0)00   k = 0

y = 00000000(1)00   k = 1

y = 0000000(1)(0)00 k = 2

y = 0000000(1)(1)00 k = 3

y = 00000(1)0(0)(0)00 k = 4

y = 00000(1)0(0)(1)00 k = 5

...

注意观察括号里的数,为x取0的比特位,而如果把括号里的数连起来看,正好等于k。

得出结论,把k表示成二进制数,填入x取0的比特位,x取1的比特位保持为0,得到y。

---代码说明---

思路有了,接着就是代码,显然用位操作是最合适的方式。

循环的思想是每次取得k的最低一位,填入到低位开始,x中比特位为0的位置上。

所以用while来判断k是否大于0,若是,说明k还未完全填完

循环体内,需要找到x当前可以填的位置,我们用bitNum来从右往左扫描x的每一位

(x & bitNum) == 0 说明x该位为0,可以把k的当前最后一位填入,用 (k & 1) 取出最后一位,用 ans += (bitNum * (k & 1)) 把k的最后一位填入到当前bitNum指向的位置。
填完后,k右移一位,去掉已经被填过的最后一位,bitNum也向左走一位,避免重复填入x的某个位置。
若x的某个位置为1,则跳过该位置,向左走一位并观察是否可以填入。
两次bitNum向左走一位,合并成一句 bitNum <<= 1;
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: