位运算的运算符
| 运算符 |
描述 |
运算规则 |
实例 |
| & |
按位与运算符 |
只有对应的两个二进位都为$ 1 ,结果位才为 1。 $ |
0001&0001=1,0001&0000=0 |
| ** |
按位或运算符 |
只要对应的两个二进位有一个为\(1,结果位就为 1。\) |
0001∣0001=0001,0001∣0000=0001 |
| ^ |
按位异或运算符 |
对应的两个二进位相异时,结果位\(为 1,二进位相同时则结果位为 0。\) |
0001∧0001=0000,0001∧0000=1 |
| ~ |
取反运算符 |
对二进制数的每个二进位取反,使\(数字 1 变为 0,0 变为 1。\) |
∼0=1,∼1=0 |
| << |
左移运算符 |
将二进制数的各个二进位全部左移若干位。\(<<\) 右侧数字指定了移动位数,高位丢弃,\(低位补 0\)。 |
0001 << 2=0100 |
| >> |
右移运算符 |
对二进制数的各个二进位全部右移若干位。\(>>\) 右侧数字指定了移动位数,低位丢弃,\(高位补 0\)。 |
0100 >> 2=0001 |
位运算的性质
优先级
从上到下优先级依次递减
| 运算符 |
结合方向 |
| −(负号运算符),∼(取反运算符),++(自增),−−(自减),&(取地址运算符) |
从右到左 |
| ∗(乘),/(除),%(取余) |
从左到右 |
| +(加),−(减) |
从左到右 |
| <<(左移),>>(右移) |
从左到右 |
| >(大于),<(小于),>=(大于等于),<=(小于等于) |
从左到右 |
| ==(等于),!=(不等于) |
从左到右 |
| &(按位与) |
从左到右 |
| ∧ (按位异或) |
从左到右 |
| ∣ (按位或) |
从左到右 |
总结:能加括号就加括号
位运算的常用操作
| 功 能(都是在二进制表示中的操作,k默认从1开始) |
位运算(对于某个数x) |
示例(默认右边为低位) |
| 去掉最后一位 |
x >> 1 |
101101 -> 10110 |
在最后加一个 0 |
x << 1 |
101101 -> 1011010 |
在最后加一个 1 |
( x << 1 ) + 1 |
101101 -> 1011011 |
把最后一位变成 1 |
x ∣ 1 |
101100 -> 101101 |
把最后一位变成 0 |
(x ∣ 1) − 1 |
101101 -> 101100 |
| 最后一位取反 |
x ∧ 1 |
101101 -> 101100 |
把右数第 k 位变成 1 |
x ∣ ( 1 << ( k − 1 )) |
101001 -> 101101, k = 3 |
把右数第 k 位变成 0 |
x & ( ∼ ( 1 << ( k − 1 ))) |
101101 -> 101001, k = 3 |
右数第 k 位取反 |
x ∧ ( 1 << ( k − 1 )) |
101001 -> 101101, k = 3 |
取末尾 k 位 |
x & (( 1 << k) − 1 ) |
1101101 -> 1101, k = 4 |
取右数第 k 位 |
(x >> k − 1 ) & 1 |
1101101 -> 1, k = 4 |
把末尾 k 位全变成 1 |
x ∣ (( 1 << k ) − 1 ) |
101001 -> 101111, k = 4 |
末尾 k 位取反 |
x ∧ (( 1 << k ) − 1 ) |
101001 -> 100110, k = 4 |
把右边连续的 1 变成 0 |
x & ( x + 1 ) |
100101111 -> 100100000 |
只保留右边连续的 1 |
(x ∧ ( x + 1 )) >> 1 |
100101111 -> 1111 |
| 提取右数最右侧的 1,其他位均为0 |
x & ( x ∧ ( x − 1 )) 或 x & ( - x ) |
100101000 -> 1000 |
从右边开始,把最后一个 1 改写成 0 |
x & ( x - 1 ) |
100101000 -> 100100000 |
例题
Luogu P1469 找筷子
传送门
#include <bits/stdc++.h>
using namespace std;
int main() {
int n;
int ans = 0;
cin>>n;
for (int i = 1; i <= n; i++) {
int x;
cin>>x;
ans ^= x;
}
cout<<ans;
return 0;
}