位运算

题单类型:官方题单
创建人:
ACGO官方
题数:20
收藏题单
完成度:0/20

位运算

1. 基础运算符

1.1 与运算(&)

  • 含义:对应位都为 11 时结果位为 11,否则为 00
  • 例:
    6=1102, 5=10126=110_2,\ 5=101_2
    6 & 5=1002=46\ \&\ 5 = 100_2 = 4

1.2 或运算(|)

  • 含义:对应位只要有一个为 11,结果位为 11
  • 例:
    6=1102, 5=10126=110_2,\ 5=101_2
    6  5=1112=76\ |\ 5 = 111_2 = 7

1.3 取反运算(~)

  • 含义:010\leftrightarrow 1(对所有位取反)
  • 例:
    5=0000010125 = 00000101_2
    5=111110102\sim 5 = 11111010_2
    (在常见补码表示下,这个结果对应十进制 6-6

1.4 异或运算(^)

  • 含义:对应位不同为 11,相同为 00
  • 例:
    6=1102, 5=10126=110_2,\ 5=101_2
    6 ^ 5=0112=36\ \hat{}\ 5 = 011_2 = 3

2. 移位运算符

2.1 左移(<<)

  • 含义:整体向左移动,低位补 00
  • 直观效果:相当于乘以 2k2^k
  • 例:
    3=0000001123=00000011_2
    32=000011002=123 \ll 2 = 00001100_2 = 12

2.2 右移(>>)

  • 含义:整体向右移动,低位被舍弃
  • 直观效果:相当于除以 2k2^k 并向下取整
  • 例:
    13=00001101213=00001101_2
    132=000000112=313 \gg 2 = 00000011_2 = 3

3. 位运算性质

3.1 异或性质(^)

  • 交换律、结合律成立
  • 自反:aa=0a \oplus a = 0
  • 00 的关系:a0=aa \oplus 0 = a
  • 可逆性:(ab)b=a(a \oplus b) \oplus b = a

3.2 与性质(&)

  • 交换律、结合律成立
  • 幂等:a & a=aa\ \&\ a = a
  • 吸收:a & 0=0a\ \&\ 0 = 0a & 全1=aa\ \&\ \text{全1} = a
  • 递减:a & bmin(a,b)a\ \&\ b \leq \min(a,b)

3.3 或性质(|)

  • 交换律、结合律成立
  • 幂等:aa=aa | a = a
  • 吸收:a0=aa | 0 = aa全1=全1a | \text{全1} = \text{全1}
  • 递增:abmax(a,b)a | b \geq \max(a,b)

4. 位运算技巧

4.1 判断某一位是否为 11

  • 思路:构造掩码 mask=1kmask=1\ll k,用与运算判断第 kk 位是否为 11
  • 表达式:x & (1k)x\ \&\ (1\ll k)
  • 例:
    x=13=11012x=13=1101_2
    • 判断第 22 位:mask=01002mask=0100_2
      11012 & 01002=0100201101_2\ \&\ 0100_2=0100_2\neq 0,所以第 22 位是 11
    • 判断第 11 位:mask=00102mask=0010_2
      11012 & 00102=00002=01101_2\ \&\ 0010_2=0000_2=0,所以第 11 位是 00

4.2 将某一位置 11 / 置 00 / 翻转

  • 11x = (1k)x\ |=\ (1\ll k)

  • 00x &= (1k)x\ \&=\ \sim(1\ll k)

  • 翻转:x ^= (1k)x\ \hat{}=\ (1\ll k)

  • 例:x=10=10102x=10=1010_2

    (1) 置第 00 位为 11
    k=0k=010=000121\ll 0=0001_2

    x=x  (10)=10102  00012=10112=11\begin{aligned} x' &= x\ |\ (1\ll 0) \\ &= 1010_2\ |\ 0001_2 \\ &= 1011_2 \\ &= 11 \end{aligned}

    (2) 置第 11 位为 00
    k=1k=111=001021\ll 1=0010_2(11)=00102=11012\sim(1\ll 1)=\sim 0010_2=1101_2

    x=x & (11)=10102 & 11012=10002=8\begin{aligned} x' &= x\ \&\ \sim(1\ll 1) \\ &= 1010_2\ \&\ 1101_2 \\ &= 1000_2 \\ &= 8 \end{aligned}

    (3) 翻转第 33 位(010\leftrightarrow 1
    k=3k=313=100021\ll 3=1000_2

    x=x ^ (13)=10102 ^ 10002=00102=2\begin{aligned} x' &= x\ \hat{}\ (1\ll 3) \\ &= 1010_2\ \hat{}\ 1000_2 \\ &= 0010_2 \\ &= 2 \end{aligned}

4.3 找最低位的 11lowbitlowbit)与删除最低位的 11

  • lowbitlowbitlowbit(x)=x & (x)lowbit(x)=x\ \&\ (-x)(提取最低位的 11 所代表的值)
  • 删除最低位的 11x & (x1)x\ \&\ (x-1)
  • 例:
    x=12=11002x=12=1100_2
    • lowbit(x)=01002 (=4)lowbit(x)=0100_2\ (=4)
    • x & (x1)=11002 & 10112=10002 (=8)x\ \&\ (x-1)=1100_2\ \&\ 1011_2=1000_2\ (=8)

4.4 统计二进制中 11 的个数

  • 方法:不断删除最低位的 11,删除次数就是 11 的个数
    操作:反复执行 x &= (x1)x\ \&=\ (x-1)
  • 例:
    x=13=11012x=13=1101_2
    11011100100000001101\rightarrow 1100\rightarrow 1000\rightarrow 0000
    33 次,所以 popcount(13)=3popcount(13)=3

4.5 判断是否为 22 的幂

  • 结论:对 x>0x>0,若 x & (x1)=0x\ \&\ (x-1)=0,则 xx22 的幂
    22 的幂在二进制中只有一个 11
  • 例:
    • 8=100028=1000_281=7=011128-1=7=0111_210002 & 01112=000021000_2\ \&\ 0111_2=0000_2,是 22 的幂
    • 12=1100212=1100_2121=11=1011212-1=11=1011_211002 & 10112=1000201100_2\ \&\ 1011_2=1000_2\neq 0,不是 22 的幂

4.6 用整数的二进制位表示集合及子集枚举

  • 集合表示(状态压缩):用一个整数 maskmask 表示集合
    • ii 位为 11:元素 ii 在集合中
    • ii 位为 00:元素 ii 不在集合中
  • 例:
    44 个元素 {0,1,2,3}\{0,1,2,3\}mask=13=11012mask=13=1101_2
    表示集合为 {0,2,3}\{0,2,3\}(第 0,2,30,2,3 位为 11

ex 子集枚举 / 超集枚举

设全集大小为 nn,全集掩码 U=(1n)1U=(1\ll n)-1

1) 子集枚举(枚举 maskmask 的所有子集 subsub

for (int sub = mask; ; sub = (sub - 1) & mask) {
    if (sub == 0) break;
}

2) 超集枚举(枚举所有 supmasksup \supseteq mask

做法:先枚举可选位 free=Umaskfree = U \oplus mask 的子集 tt,再令 sup=masktsup = mask \mid t

int free = U ^ mask;
for (int t = free; ; t = (t - 1) & free) {
    int sup = mask | t;
    if (t == 0) break;
}

5. 常用函数

5.1 统计二进制中 11 的个数(popcount)

  • __builtin_popcount(x)
  • __builtin_popcountll(x)

5.2 末尾连续 00 的个数(ctz)

  • __builtin_ctz(x)
  • __builtin_ctzll(x)
  • 注意:当 x=0x=0 时结果未定义(调用前需保证 x0x\neq 0

5.3 前导连续 00 的个数(clz)

  • __builtin_clz(x)
  • __builtin_clzll(x)
  • 注意:当 x=0x=0 时结果未定义(调用前需保证 x0x\neq 0

5.4 最高位 11 的位置(00-based)

  • x>0x>0
    pos = 31 - __builtin_clz(x)3232 位)
    pos = 63 - __builtin_clzll(x)6464 位)

5.5 最低位 11 的位置(00-based)

  • x>0x>0
    pos = __builtin_ctz(x)3232 位)
    pos = __builtin_ctzll(x)6464 位)

【前置知识点】
1、进制转换

【思维导图】

【题目知识点分类】