位运算

关于lowbit运算的相关知识

本篇随笔简单讲解一下计算机中位运算的一类重要运算方式——lowbitlowbit运算。

lowbit的概念

我们知道,任何一个正整数都可以被表示成一个二进制数。如:

 

(2)10=(10)2(2)10=(10)2

 

 

(4)10=(100)2(4)10=(100)2

 

 

 

那么定义一个函数f=lowbit(x)f=lowbit(x),这个函数的值是xx的二进制表达式中最低位的11所对应的值。

比如:

 

(6)10=(110)2(6)10=(110)2

 

那么lowbit(6)lowbit(6)就等于22,因为(110)2(110)2中最低位(就是从右往左数的第二位)对应的数是21=221=2

所以假设一个数的二进制最低位的11在从右往左数的第kk位,那么它的lowbitlowbit值就是

 

2k12k−1

 

lowbit函数的实现

lowbit函数实现有两种方式:

一、

x&(x^(x-1))

二、

x&-x

简单解释一下:

我们得到lowbit的值,只需要得到最后一个1的位置,并且把除了这个位置之外的所有位置全部置成零。然后输出就可以。

那么我们看一看x&(x^(x-1))

拿上面的6举例:

 

(110)21=(101)2(110)2−1=(101)2

 

我们发现,根据小学数学减法运算的借位原则(滑稽),对一个二进制数进行减1,那么会出现从这个这个数的最后一个1开始到最后的所有数都取反,即构成一个0111101111⋯的串。

我们把这个数与原数异或,就会造成:第一个1以后的数(包括第一个1)全部取1.其他的位全部取0.即构成一个由一堆0后面跟一堆1的串。

那么再把原式做一个与运算,那么除了原来的那个1(对应位都是1)为1,其他位全是0,完成任务。

那么我们再看一看x&-x

根据计算机补码的性质。

补码就是原码的反码加一

如:

 

(110)2=6(110)2=6

 

反码:

 

(001)2(001)2

 

加一:

 

(010)2(010)2

 

可以发现变为反码后 x 与反码数字位每一位都不同, 所以当反码加1后神奇的事情发生了,反码会逢1一直进位直到遇到0,且这个0变成了1,所以这个数最后面构造了一个 100… 串。 由于是反码,进位之后由于1的作用使进位的部分全部取反及与原码相同,所以可以发现 lowbit 以前的部分 x 与其补码即 -x 相反, lowbit x 与 -x 都是1,lowbit 以后 x 与 -x 都是0 所以 x&-x 后除了 lowbit 位是1,其余位都是0。符合条件。

用lowbit运算统计1的个数

我们可以使用lowbit运算统计一个整数的二进制形式下1的个数。

实现原理很简单啦,就是:我们先用lowbit运算找出lowbit(x)lowbit(x),然后用原数减去这个数,依次循环,直到为0为止。

这也是树状数组的实现原理。

代码:

while(x)
{
	x-=x&-x;
	ans++;
}

(巨短无比)

lowbit运算的应用

关于lowbit运算,最著名的应用应该算是树状数组。但是lowbit的神妙远远不止树状数组,在很多二进制和位运算的相关题目中,都有lowbit运算的影子。甚至,在状态压缩DP中,lowbit也扮演着一份不可忽视的角色。

 

末尾清0

x&(x-1)

https://blog.csdn.net/weibo1230123/article/details/75910325

https://blog.csdn.net/qq_41822235/article/details/81349232

lowbit -取最后一个1及其后面的0组成的数

x & -x

 

posted @ 2021-09-21 03:11  new-code  阅读(68)  评论(0编辑  收藏  举报