0x01 位运算(1)

0x01 位运算(1)

本节主要内容:

第一部分:补码反码、移位运算、快速幂、快速乘法

第二部分:二进制状压、成对变换、lowbit()运算,Barrett模乘(补充)

一、 补码与反码

1. 补码

开头一个符号位,其余为数值位

32位补码表示 unsigned int int
000000...000000 0 0
0111111...111111 2147483647 2147483647
100000...000000 2147483678 -2147483648
111111...111111 4294967295 -1

1. 反码

开头一个符号位,其余为数值位

32位反码表示 32位整数
000000...000000 0
111111...111111 0
011111...111111 2147483647
100000...000000 -2147483647

二、 移位运算

  1. 算术右移:高位以符号位补充,低位越界舍弃

  2. 逻辑右移:高位以0补充,低位越界舍弃

三、 快速幂取模

此时尝试计算

\[a^bmod\\quad p \]

这是一个典型的求幂运算,在一些与数学有关的问题中极为常见。

通常使用循环方法求幂,时间复杂度为O(b),然而众所周知,取模运算的速度极慢,这种暴力方法不足以满足我们的需求,我们需要尽可能减少运算次数。

接下来介绍利用位运算加速的求幂方法,先给出理论推导

假设指数b在二进制下表示为

\[b\_{(2)} = \\overline{c\_{k-1}c\_{k-2} \\dots c\_0} \]

写为多项式,即为

\[b = c\_{k-1} \\cdot 2^{k-1} + c\_{k-2} \\cdot 2^{k-2} + \\dots + c\_0\\cdot2^0 \]

从而

\[\\begin{aligned} a^b &= a^{c\_{k-1}\\cdot{2^{k-1}}} \* a^{c\_{k-2}\\cdot{2^{k-1}}}\*\\dots\*a^{c\_0\*2^0}\\\\ &=(a^{c\_{k-1}\\cdot{2^{k-2}}} \* a^{c\_{k-2}\\cdot{2^{k-3}}}\*\\dots\*a^{c\_1\*2^0})^2\*a^{c\_0\\cdot2^0}\\\\ &=((a^{c\_{k-1}\\cdot{2^{k-3}}} \* a^{c\_{k-2}\\cdot{2^{k-4}}}\*\\dots\*a^{{c\_2}\*2^0})^2\*a^{c\_1\*2^0})^2\*a^{c\_0\\cdot2^0}\\\\ &=\\dots\\\\ &=(((a^{c\_{k-1}\\cdot2^0})^2\*a^{c\_{k-2}\\cdot2^0})^2\*\\dots)^2\*a^{c\_0\\cdot2^0}\\\\ &=(((a^{c\_{k-1}})^2\*a^{c\_{k-2}})^2\*\\dots)^2\*a^{c\_0} \\end{aligned} \]

于是,可以用下面的代码求出a^b:

int power(int a,int b){   //calculate a^b
int ans = 1;
while(b){
if (b & 1) ans *= a;
a *= a;
b >>= 1;
}
return ans;
}

同时,考虑到

\[a\\cdot b \\quad \\%p == a\\%p\\quad\\cdot\\quad b\\%p \]

则在循环中每次计算取模

int power(int a,int b, int p){   //calculate a^b
int ans = 1 % p;
while(b){
if (b&1) ans = (ll)ans * a  % p;//暂时转化为ll,以免越界,赋值时再转化回int
a = (ll)a * a % p;
b >>= 1;
}
return ans;
}

从而,我们计算出a^b mod p,时间复杂度为O(log2b)

四、 64位整数乘法

题目链接:64位整数乘法——ACWing

类似于快速幂取模,我们用相似的方法处理乘法。

此时尝试计算

\[ab\\quad mod\\quad p \]

假设b在二进制下表示为

\[b = \\overline{c\_{k-1}c\_{k-1}\\dots c\_0} \]

写为多项式,即为

\[b = c\_{k-1} \\cdot 2^{k-1} + c\_{k-2} \\cdot 2^{k-2} + \\dots + c\_0 \\cdot 2^0 \]

从而

\[\\begin{aligned} ab &= ac\_{k-1}\\cdot 2^{k-1}+ac\_{k-2}\\cdot2^{k-2}+\\dots+ac\_0\\cdot2^0\\\\ &= (ac\_{k-1}\\cdot 2^{k-2} + ac\_{k-2}\\cdot2^{k-3}+\\dots+ac\_1\\cdot2^0)\*2+ac\_0\\cdot2^0\\\\ &= ((ac\_{k-1}\\cdot 2^{k-3} + ac\_{k-2}\\cdot2^{k-4}+\\dots+ac\_2\\cdot2^0)\*2+ac\_1\\cdot2^0)\*2+ac\_0\\cdot2^0\\\\ &=\\dots\\\\ &=(((ac\_{k-1}\\cdot2^0)\*2+ac\_{k-2}\\cdot2^0)\*2+\\dots)\*2+ac\_0\\cdot2^0\\\\ &=((ac\_{k-1}\*2+ac\_{k-2})\*2+\\dots)\*2+ac\_0\\\\ &=\[((c\_{k-1}\*2+c\_{k-2})\*2+\\dots)\*2+c\_0\]\\cdot a\\\\ \\end{aligned} \]

于是,可以用下面的代码求出ab

ll mul(ll a, ll b){
   ll ans = 0;
   while(b){
       if (b & 1) ans += a;
       a *= 2;
       b >>= 1;
  }
   return ans;
}

考虑取模:

ll mul(ll a, ll b){
   ll ans = 0;
   while(b){
       if (b & 1) ans = (ans + a) % p;
       a = a * 2 % p;
       b >>= 1;
  }
   return ans;
}

从而,我们计算出ab mod p,时间复杂度为O(log2b)

本文由“庞加莱复现”原创,未经允许,严禁转载!

如果觉得本文对你有用,不妨点赞收藏一下吧!

posted @ 2026-07-20 14:48  庞加莱复现  阅读(1)  评论(0)    收藏  举报