题目翻译:一个数字x的二进制有a个1,求第一个比x大的数字,让1的数量也是a
思路:从低位到高位,找到第一个01,改成10,并把10后面的所有的1移到低位就可以了
比如1001110
第一个01是第3位和第4位的(从0开始数),变成10,1010110,10后面有2个1,移到低位就是1010011,这个就是答案了
具体解题方法,x=n&(-n)可以获得最低位的1
因为,如果1是第0位,反码就是取反,就变成了0,补码再加1就是最低位的1,
如果1后面有多个0(100000),反码取反就是0后面多个1(011111),补码+1之后会进位到第一个1(100000),
例如n=0100110
-n原码是1100110,
-n反码是1011001,
-n补码是1011010,
n&(-n)=10
得到了最低位的1,我们要把01变成10,具体做法就是n+x
因为如果原本01000这样的,那么n+x就会进位成10000,
如果原本是0111110这样的,那么n+x就会进位成1000000
例如n=0100110,n+x就是0101000
将01变成10之后我们也把10后面的1都变成了0,我们要补回来,这时候我们想到了异或,相同为0,不同为1,n^(n+x)这时候可以获得原本是0由n+x变成1的0,
例如n=0100110,n+x变成了0101000,第1位的1变成了0,n^(n+x)会变成0001110
这时候吧所有的1移到低位,也就是n^(n+x)/x
例如0001110,或变成111,
由于之前异或的时候01和10异或会变成11,也就是多了2个1,这时候我们右移两位(n^(n+x))/x>>2,这样就可以吧10后面的1都移到低位
所以答案就是x=n&(-n),result=n+x+(n^(n+x))/x>>2;
ac代码
#include<stdio.h>
int main(){
int n,x;
while(scanf("%d",&n)&&n){
x=n&(-n);
printf("%d\n", n + x + ((n ^ (n + x)) / x >> 2));
}
return 0;
}