文章目录
- 位运算简介
- 与运算&
- 或运算|
- 异或运算^
- 证明
- 取反~
- 左移<<
- 右移>>
- 位运算技巧
- 判断奇偶性
- 求出x二进制的第i位
- 将二进制的第i位设置成1
- 将二进制的第i位设置成0
- 判断是否为2的若干次方
- 获取x的最低位的1
- 用lowbit运算统计1的个数
- 例题
位运算简介
位运算:面向二进制的计算,二进制的位数是从0开始(右到左)
- 与运算:有0得0(有一个是假的,结果就是假的)
- 或运算:有1得1(有一个是真的,结果就是真的)
- 异或运算:相同为0,不同为1(相同结果为假,不同结果为真)
- 取反
- 左移、右移
与运算&
x | y | x&y |
---|---|---|
0 | 0 | 0 |
0 | 1 | 0 |
1 | 0 | 0 |
1 | 1 | 1 |
6&11=0110&1011=0010=2
或运算|
x | y | x/y |
---|---|---|
0 | 0 | 0 |
0 | 1 | 1 |
1 | 0 | 1 |
1 | 1 | 1 |
6|11=0110|1011=1111=15
异或运算^
0 | 0 | 0 |
---|---|---|
0 | 0 | 0 |
1 | 0 | 1 |
0 | 1 | 1 |
1 | 1 | 0 |
- 交换律:
x^y=y^x
- 结合律:
x^(y^z)=(x^y)^z
- 自反性:
x^x=0
- 零元素:
x^0=x
- 逆运算:
x^y=z-->z^y=x
证明
对于交换律,很显然,异或是比较xy是否有不同,跟位置没关系。
对于结合律,异或是比较xyz……是否有不同,跟位置没关系。
比如(1^1)^0=0^0=0
1^(1^0)=1^1=0
(1^1)^1=0^1=1
1^(1^1)=1^0=1
只要有一个不同,就变成1,如果又遇到相同的,就变成0,直到变完为止……
这种相同以及不同的关系跟位置没啥关系。
对于零元素,当x=1,1^0=1
,当x=0,0^0=0
。
对于自反性,根据异或运算定义,x=x,所以x^x=0
。
对于逆运算,x^y=z-->x^y^y=z^y-->x^0=x=z^y
取反~
把二进制的0变成1,1变成0
~6= ~0110=1001=9
~1=0001=1110=
左移<<
二进制向左移动指定位数
每次左移一位,相当于乘上2
5=0000 0101
5<<3=0010 1000=40
右移>>
每次右移一位,相当于除以2
13=1101
13>>2=0011=3
位运算技巧
判断奇偶性
- 对2求余数:x%2
- 直接判断二进制的第0位是1或者0
- 相当于直接判断x&1
13&1=1101&0001=0001 所以13%2=1
12%1=1100&0001=0000 所以12%2=0
求出x二进制的第i位
- 已知获取第0位:直接&1
- 那先把第i位转成第0位(右移i位),再求第0位就可以得到原来的第i位
(x>>i)&1
假如需要求19的第三位是多少。
(19>>3)&1=(0001 0011>>3)&0000 0001=0000 0010&0000 0001=0000 0000=0
将二进制的第i位设置成1
x|(1<<i)
原理:把1左移到第i位和x的第i位对应,此时已经有一方是1,或运算后值的第i位一定是1,其他位和0进行或运算得到原来的值。
比如把19的第三位设置成1
19|(1<<3)=0001 0011|(0000 0001<<3)=0001 0011|00001000=0001 1011=27
将二进制的第i位设置成0
x&~(1<<i)
原理:把1左移到第i位和x的第i位对应,取反后除了第i位是0,其他都是1,再和x进行与运算,只要x是1的最后还是1,x是0的最后还是0,x的第i位一定是0.
比如把19的第四位设置成0
19&~(1<<4)=0001 0011& ~(0001 0000)=0001 0011&1110 1111=0000 0011=3
判断是否为2的若干次方
- 判断
x&(x-1)
是否为0 - 原理:2的若干次方进制表示只存在一个1。
如果x&(x-1)=0说明二进制中只有1个1.
获取x的最低位的1
Lowbit(x)=x&(-x)
这个函数的值是x的二进制表达式中最低位的1所对应的值。
这里涉及二进制的负数。
二进制的负数用补码表示,补码就是取其绝对值的二进制表示(即正数的二进制表示),然后取反(0变1,1变0),最后加1得到。
如果求-8的二进制写法:
- 先求出+8的二进制:0000 0100
- 取反:1111 1011
- 加1:1111 1100
以二进制表示+12是0000 1100;
以二进制表示-8是1111 1000;
12-8=0000 0100=4
进位会传递到最左边的所有1上,把他们同时设置为0
回到Lowbit(x)=x&(-x)
,可以发现变为反码后 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的个数
ans=0
while x:
x-=x&(-x)
ans+=1
例题
lanqiao1331 二进制中 1 的个数
lanqiao3691 区间或
lanqiao3440 异或森林