初赛位运算
以下摘自洛谷日报
“<<” “>>” 运算
首先,在这里这东西跟 cin cout 没有什么关系。
在二进制运算中,这东西叫做“左移”“右移”运算,顾名思义,就是将一个二进制数向左或向右移动 k 位,就是给一个数乘 2^k 或者除 2^k (末尾1不计)。
那么这东西有什么用呢?这东西快啊
“~”运算
又称取反运算,就是对一个二进制数按位取反。
对于 int 来说, ~ x=-x-1
那么这东西有什么用呢?我也不知道
“&”运算
“&”运算,即“and” 运算,也是一种逻辑运算符,对于二进制运算来说,“&”运算的意义是对于两个二进制数的每一位,如果这一位都是 1 ,那么这一位为 1 ,否则这一位为 0 。
举个例子
10101(21) & 11100(28) = 10100{20}
我们可以用 & 运算判断一个数是奇数还是偶数,当 x 为奇数时, x 二进制下的第 0 位一定是 1 ,否则为 0 。我们让 x & 1 ,就可以知道 x 的奇偶性了。
“|” 运算
即 “or” 运算,也是一种逻辑运算符,对于二进制运算来说,“|” 运算的意义是对于两个二进制数的每一位,如果这两个数此位有一个 1 那么此位就是 1 ,否则为 0 。
举个例子
10101(21) | 11100(28) = 11101(29)
通过对这两个运算的观察,我们可以发现一个规律
x & y<=xx | y>=x
根据二进制的性质很容易就可以得出这些结论吧
“^”运算
“^”运算,又称“xor”运算,异或运算。定义是对于两个二进制数的每一位,如果相同则为 0 ,否则为 1 。
举个例子
10101(21) ^ 11100(28) = 1001(9)
异或是一个非常神奇的东东
首先显而易见的是一个数异或他自己肯定是得 0 的
其次对于一个形如 2n 的数 x , x ^ 1 =x+1 ,而对于一个形如 2n+1 的数 x , x ^ 1 =x-1
然后异或运算满足以下交换律
如果 x ^ y=z 那么 y ^ z=x , x ^ z=y
异或运算还是比较常用到的,简单举两个例子
例题一
给你 n 个数,其中只有一个数出现过一次,其余都成对出现,问只出现过一次的那个数是那个数。
原题 P1469 找筷子(https://www.luogu.org/problemnew/show/P1469)
利用异或的性质 x ^ x=0 ,将所有数异或起来,最后剩下来的那个数就是答案了。
例题二
计算 1 ^ 2 ^ 3 ^ 4 ^ … ^ n 的值
原题 P3908 异或之和(https://www.luogu.org/problemnew/show/P3908)
首先最开始是 1 ,根据异或的性质,我们可以知道 (2n) ^ 1 是等于 2n+1 的
于是我们又回到了 1 ,所以可以得出答案是以 4 为周期循环的。
------------
接下来厉害的来了,这三种运算是可以互相转换的
x|y= ~ (( ~ x) & ( ~ y))
x & y= ~ (( ~ x)|( ~ y))
x ^ y=(x|y)-(x & y)=x+y-((x & y)<<1)
但这东西似乎除了能让你感受到位运算的博大精深以外似乎什么用都没有
洛谷日报结束
位运算大部分人都知道,看一道18年初赛题:
14. 为了统计一个非负整数的二进制形式中 1 的个数,代码如下:
int CountBit(int x)
{
int ret = 0;
while (x)
{
ret++;
___________;
}
return ret;
}
则空格内要填入的语句是( )。
A. x >>= 1
B. x &= x - 1
C. x |= x >> 1
D. x <<= 1
答案为B
这种题思路就是先举1个数,再一个一个代入。
如9
二进制为 1001
A选项只会一次删掉一位
1001
100
10
1
答案为4,排除
B选项
1001 & 1000 = 1000
1000 & 0111 = 0
答案为2,正确
C选项 错
D选项 死循环,与A类似