位运算

题单类型:官方题单
创建人:
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 取反运算(~)

  • 含义:0↔10\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
    3≪2=000011002=123 \ll 2 = 00001100_2 = 12

2.2 右移(>>)

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

3. 位运算性质

3.1 异或性质(^)

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

3.2 与性质(&)

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

3.3 或性质(|)

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

4. 位运算技巧

4.1 判断某一位是否为 11

  • 思路:构造掩码 mask=1≪kmask=1\ll k,用与运算判断第 kk 位是否为 11
  • 表达式:x & (1≪k)x\ \&\ (1\ll k)
  • 例:
    x=13=11012x=13=1101_2
    • 判断第 22 位:mask=01002mask=0100_2
      11012 & 01002=01002≠01101_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 / 翻转

  • 置 11:x ∣= (1≪k)x\ |=\ (1\ll k)

  • 置 00:x &= ∼(1≪k)x\ \&=\ \sim(1\ll k)

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

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

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

    x′=x ∣ (1≪0)=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=1,1≪1=001021\ll 1=0010_2,∼(1≪1)=∼00102=11012\sim(1\ll 1)=\sim 0010_2=1101_2

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

    (3) 翻转第 33 位(0↔10\leftrightarrow 1)
    k=3k=3,1≪3=100021\ll 3=1000_2

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

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

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

4.4 统计二进制中 11 的个数

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

4.5 判断是否为 22 的幂

  • 结论:对 x>0x>0,若 x & (x−1)=0x\ \&\ (x-1)=0,则 xx 是 22 的幂
    (22 的幂在二进制中只有一个 11)
  • 例:
    • 8=100028=1000_2:8−1=7=011128-1=7=0111_2,10002 & 01112=000021000_2\ \&\ 0111_2=0000_2,是 22 的幂
    • 12=1100212=1100_2:12−1=11=1011212-1=11=1011_2,11002 & 10112=10002≠01100_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=(1≪n)−1U=(1\ll n)-1。

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

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

2) 超集枚举(枚举所有 sup⊇masksup \supseteq mask)

做法:先枚举可选位 free=U⊕maskfree = U \oplus mask 的子集 tt,再令 sup=mask∣tsup = 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 时结果未定义(调用前需保证 x≠0x\neq 0)

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

  • __builtin_clz(x)
  • __builtin_clzll(x)
  • 注意:当 x=0x=0 时结果未定义(调用前需保证 x≠0x\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、进制转换

【思维导图】

【题目知识点分类】