位运算呗
位运算呗
位运算,基础运算(CSP要考哦):
| 运算符 | ||
|---|---|---|
| & | 与 | 如果两个相应的二进制位都为 (1) ,则该位的结果值为 (1) ,否则为 (0) |
| | | 或 | 两个相应的二进制位中只要有一个为 (1) ,该位的结果值为 (1) |
| ^ | 异或 | 若参加运算的两个二进制位值相同则为 (0) ,否则为 (1) |
| ~ | 反 | ~是一元运算符,用来对一个二进制数按位取反,即将 (0) 变 (1) ,将 (1) 变 (0) |
| << | 左 | 用来将一个数的各二进制位全部左移 (N) 位,右补 (0) |
| >> | 右 | 将一个数的各二进制位右移 (N) 位,移到右端的低位被舍弃,对于无符号数,高位补 (0) |
注意,异或优先级高于或哦
与的特殊用法
1.判断奇偶(速度比%2要快)
N&1==1,说明为奇数,若为0,则说明为偶数;
2.异或翻转二进制
将对应的位数异或1即可。
3.寻找最低位“1”
例如n,n&(-n)就是最低位的“1”所代表的数,如110(2进制)找出来就是4(10进制)
4.<<与>>求2次幂
k<<n=k*2的n次方
k>>n=k/2的n次方
5.常用位运算的技巧
| 用途 | |
|---|---|
| n&(n−1)==0 | 判断一个数是否为 2 的幂 |
| n&(−n) | 获得一个数二进制的最后一个为 1的bit |
| n&((1<<x)−1) | 求 n mod 2x |
| (x xor y)>=0 | 判断两个数符号是否相同 |
以下为我认为有思维难度的题目
1.位移运算
给出两个数a,b。问a能否只通过位移运算( >>和 << 可以多次使用)变成b。如果可以输出"Yes",否则输出"No"。
输入格式
第一行:一个数 t ( 1≤t≤100000)。 第2 ~ t+1行:每行2个a,b中间用空格分隔(0≤a, b≤10^9)。
输出格式
输出共t行,对应答案的"Yes"和"No"
输入样例
4
4 2
2 4
3 4
1 3
输出样例
Yes
Yes
Yes
No
数据范围
对于20%的数据,1≤t≤50,0≤a, b≤20; 对于40%的数据,1≤t≤2000; 对于100%的数据,1≤t≤100000,0≤a, b≤10^9;
思路:
先来分析一下位移操作可以做什么。
- 使用 <<去掉当前数的高位的 1 。
- 使用 >>去掉当前数的低位的 1。
所以位移操作只能够去掉 a 中高位或低位的 1 。当然在去掉 1 后,我们可以通过反向位移,相当于将原本在低位或高位的 1 变为 0 。
如果 a 可以变成 b ,则去掉 b 的前导 0 和尾部的 0 (暴力第一个 1 和最后一个 1 )。得到的 0101 串 b′b′ 一定是 a 的子串。
我们可以利用 && 和 lowbit 来快速判断b′ 是否为 a 的子串。方法如下:
去掉 b 尾部的 0 得到 b′ 。
利用循环对 a 进行 >> 操作得到 a′a′ ,如果 b′ & a′=b′ ,则表明所有 b′ 为 1 的位, a′ 在相同位置的值也是 1 。r然而这还不是 b′ 为 a′ 子串的充分条件,因为还存在这种情况:
10011 & 10001=10001 。但后者不是前者的子串。
我们还要看 a′ xor b′ 得到的 c ,如果 c 最后一个 1 比 b′ 最高位的 11 位置更高,才表明b′ 为a′ 的子串。
例如:
10011 & 10001=10001 ,110011 xor 10001=100010 。
获取最低位的 1 得到 10 。 10<10001 所以不是子串。
利用这两个方法,就可以快速的判断 a 是否能够通过位移操作变成 b 了。
说白了,就是判断01子集是否相同,用位运算处理一切变换即可
实现代码:(未完待续)

浙公网安备 33010602011771号