逆元,除法同余原理

🎬 博主名称个人主页

🔥 个人专栏 : 《算法通关》

⛺️心简单,世界就简单

引言

这篇其实是寒假时候的一个博弈论问题,里面设计到了逆元,除法同余原理,我的补题内容,但是一种拖,现在当存稿补充一下发了

在组合数学或算法题中,我们常会遇到需要对含有除法的表达式取模的情况。然而,与加、减、乘法不同,除法在模运算下并不遵循简单的规则。如果不加处理,直接对除法的中间结果取模,将得到错误的答案。

加减乘的同余原理

在处理涉及模运算(取余运算)的算法问题时,加、减、乘法遵循直观且一致的运算规则,这使得我们可以在运算过程中安全地进行取模操作,从而有效防止大数溢出,并简化计算。

核心规则

设模数为 mod(一个正整数),对于整数 ab,以下规则成立:

  1. 加法同余规则
    (a % mod + b % mod) % mod = (a + b) % mod

    这意味着:两个数相加再取模的结果,等于它们各自取模后相加,再对和取模的结果。

  2. 减法同余规则
    (a % mod - b % mod) % mod = (a - b) % mod

    这意味着:两个数相减再取模的结果,等于它们各自取模后相减,再对差取模的结果。

    注意 :由于编程语言中 % 运算对负数的处理方式,为确保结果落在 [0, mod-1] 的非负范围内,当 (a % mod - b % mod) 为负数时,通常需要加上一个 mod 进行调整。

  3. 乘法同余规则
    (a % mod) * (b % mod) % mod = (a * b) % mod

    这意味着:两个数相乘再取模的结果,等于它们各自取模后相乘,再对积取模的结果。


除法同余原理

一、问题引入:为什么不能直接对除法取模?

考虑计算 (10 / 5) % 3。实际结果为:

  1. 10 / 5 = 2

  2. 2 % 3 = 2

但如果直接对分子和分母分别取模:

  1. 10 % 3 = 1

  2. 5 % 3 = 2

  3. (1 / 2) % 3 = 0

显然 0 ≠ 2,结果错误。这是因为除法不满足同余定理的直接推广。


二、解决方案:引入乘法逆元

要解决这个问题,我们需要引入乘法逆元的概念。其核心思想是:在模运算中,将除法转换为乘法。

关键转换

在模 MOD 意义下,计算 (a / b) % MOD 等价于计算:
(a * inv(b)) % MOD

其中 inv(b)b 在模 MOD 意义下的乘法逆元,满足:
(b * inv(b)) % MOD = 1

换句话说,inv(b) 在模 MOD 意义下起到了 1/b 的作用。


三、使用乘法逆元的前提条件

要使上述转换成立,必须满足以下三个条件:

  1. 整除性a / b 必须为整数(即 a 能被 b 整除)。

  2. 模数为质数MOD 必须是质数(例如常见的 1000000007)。

  3. 互质条件bMOD 必须互质(即最大公约数为1)。

在实际问题中,条件2和3通常由题目保证,条件1则需要我们在设计算法时自行确保。


四、如何计算乘法逆元?

MOD 为质数时,根据费马小定理b 的乘法逆元可以通过快速幂计算:
inv(b) = b^(MOD-2) % MOD

计算示例

5 在模 3 意义下的逆元:
inv(5) = 5^(3-2) % 3 = 5^1 % 3 = 2

验证:(5 * 2) % 3 = 10 % 3 = 1,满足逆元定义。


五、实战应用:对除法进行模运算

现在我们可以正确计算 (10 / 5) % 3

  1. 计算 5 的逆元:inv(5) = 2

  2. 计算 (10 * inv(5)) % 3 = (10 * 2) % 3 = 20 % 3 = 2

这与直接计算 (10 / 5) % 3 = 2 的结果一致。

关键优势:可对中间结果取模

当处理大数时,例如计算组合数 C(100, 50),其分子分母的阶乘(如 100!)会远远超过 long long 的范围。通过逆元将除法转换为乘法,我们可以在每一步都进行取模运算,避免数值溢出。

转换后的计算方式:
(a / b) % MOD = ((a % MOD) * (b^(MOD-2) % MOD)) % MOD

这样,即使 ab 很大,我们也可以安全地计算。


六、关于指数运算的说明

你可能会担心 b^(MOD-2) 的指数很大(例如 MOD=1000000007)。实际上,我们可以通过快速幂算法O(log MOD) 时间内高效计算,并在计算过程中不断取模,确保不会溢出。

七、总结与记忆要点

当题目满足以下条件时:

  1. 需要计算 (a / b) % MOD

  2. MOD 是质数(如 1000000007

  3. bMOD 互质

  4. a 能被 b 整除

我们可以按以下步骤计算:

  1. 计算 b 的逆元:inv(b) = b^(MOD-2) % MOD

  2. 计算最终结果:(a % MOD) * inv(b) % MOD

核心公式
(a / b) % MOD = (a % MOD) * (b^(MOD-2) % MOD) % MOD

记住这个公式,你就可以在算法竞赛中安全地处理除法取模问题了。


补充说明:在实际编程中,通常会将逆元计算封装为函数,并利用快速幂算法高效求解。这样既能保证正确性,又能应对大规模数据。

cpp 复制代码
long power(long b,int n,int mod){
	long ans=1;
	while(n>0){
		if((n&1)==1){
			ans=(ans*b)%mod;
		}
		b=(b*b)%mod;
		n>>=1;
	}
	return ans;
} 

下面是除法同余原理

cpp 复制代码
long power(long b,int n,int mod){
	long ans=1;
	while(n>0){
		if((n&1)==1){
			ans=(ans*b)%mod;
		}
		b=(b*b)%mod;
		n>>=1;
	}
	return ans;
} 
int f(long a,long b,int mod){
	long inv =power(b,mod-2,mod);
	return (int)(((a%mod)*inv)%mod);
}
相关推荐
leiming62 小时前
c++ 利用模板创建一个可以储存任意类型数据的数组类
开发语言·c++·算法
TL滕2 小时前
从0开始学算法——第二十天(简易搜索引擎)
笔记·学习·算法
cpp_25012 小时前
P8723 [蓝桥杯 2020 省 AB3] 乘法表
数据结构·c++·算法·蓝桥杯·题解·洛谷
再__努力1点2 小时前
【76】Haar特征的Adaboost级联人脸检测全解析及python实现
开发语言·图像处理·人工智能·python·算法·计算机视觉·人脸检测
溟洵2 小时前
【算法C++】链表(题目列表:两数相加、两两交换链表中的节点、重排链表、合并 K 个升序链表、K 个一组翻转链表7)
数据结构·c++·算法·链表
_OP_CHEN2 小时前
【C++数据结构进阶】玩转并查集:从原理到实战,C++ 实现与高频面试题全解析
数据结构·c++·算法
gugugu.2 小时前
算法:hot100---128. 最长连续序列
算法
天呐草莓2 小时前
支持向量机(SVM)
人工智能·python·算法·机器学习·支持向量机·数据挖掘·数据分析
zore_c2 小时前
【数据结构】队列——超详解!!!(包含队列的实现)
c语言·网络·数据结构·c++·笔记·算法·链表