Modular Arithmetic 模运算
Modular Arithmetic 模运算
简介
在模运算中,我们不是直接处理整数本身,而是处理它们除以 后的余数。我们称这个过程为取模 。例如,如果我们取 ,那么我们不是处理 ,而是使用 。
通常, 会是一个大素数,题目中会给出;最常见的两个值是 和 。
模运算用于避免处理会溢出内置数据类型的数字,因为我们可以根据以下公式取余数:
模幂运算
为什么需要快速幂?
计算 时,如果直接使用循环乘 次,时间复杂度是 。但当 达到 甚至更大时,这种方法就太慢了。
二进制幂次方
二进制幂次方(Binary Exponentiation)可以将时间复杂度降到 。
核心思想:将指数 分解为二进制表示。例如:
如果我们知道 ,就可以用 的时间计算出 。
实现
MOD = 10**9 + 7
def pow_mod(a, b, mod):
"""计算 a^b mod mod"""
res = 1
a %= mod
while b:
if b & 1:
res = res * a % mod
a = a * a % mod
b >>= 1
return resPython 内置的 pow
函数已经实现了快速幂,可以直接使用:
MOD = 10**9 + 7
for _ in range(int(input())):
first, second = map(int, input().split())
print(pow(first, second, MOD))模逆元
什么是模逆元?
模逆元相当于实数中的倒数。要将 除以 ,可以乘以 的模逆元。
对于素数模 , 的模逆元定义为满足以下条件的数 :
例如, 模 的逆元是 。
验证:
费马小定理
费马小定理(不要与费马大定理混淆)指出,所有不被 整除的整数 都满足:
因此:
所以 就是 模 的逆元。
实现
MOD = 10**9 + 7
# 方法1:使用费马小定理
x = pow(2, MOD - 2, MOD)
print(x) # 500000004
assert 2 * x % MOD == 1扩展欧几里得算法
我们也可以通过扩展欧几里得算法求模逆元:
def modinv(x, mod):
"""扩展欧几里得算法求模逆元"""
if x <= 1:
return x
return mod - mod // x * modinv(mod % x, mod) % mod预计算逆元
如果需要频繁计算多个数的模逆元,可以利用以下递推公式预计算:
MOD = 10**9 + 7
inv = [0] * MOD
inv[1] = 1
for i in range(2, MOD):
inv[i] = MOD - MOD // i * inv[MOD % i] % MOD这样可以在 时间内预处理所有 范围内数的逆元,之后每次查询只需 。
注意事项
- 除零错误:必须确保不尝试除以 0
- 取模后的零:要注意在应用模运算后,一个非零数可能会变成零,因此在对非常数值进行除法运算时要格外小心
- 性能:由于计算模逆元需要 的时间,在循环内部频繁使用除法会显著增加程序的运行时间。如果多次使用同一个数的模逆元,预先计算它是更好的选择
Modular Arithmetic 模运算
https://mingsm17518.github.io/2026/04/30/算法学习/05_Gold/01_Math/02_Modular Arithmetic 模运算/