🎬 博主名称 :个人主页
🔥 个人专栏 : 《算法通关》
⛺️心简单,世界就简单

引言
这篇其实是寒假时候的一个博弈论问题,里面设计到了逆元,除法同余原理,我的补题内容,但是一种拖,现在当存稿补充一下发了
在组合数学或算法题中,我们常会遇到需要对含有除法的表达式取模的情况。然而,与加、减、乘法不同,除法在模运算下并不遵循简单的规则。如果不加处理,直接对除法的中间结果取模,将得到错误的答案。
加减乘的同余原理
在处理涉及模运算(取余运算)的算法问题时,加、减、乘法遵循直观且一致的运算规则,这使得我们可以在运算过程中安全地进行取模操作,从而有效防止大数溢出,并简化计算。
核心规则
设模数为 mod(一个正整数),对于整数 a 和 b,以下规则成立:
-
加法同余规则
(a % mod + b % mod) % mod = (a + b) % mod这意味着:两个数相加再取模的结果,等于它们各自取模后相加,再对和取模的结果。
-
减法同余规则
(a % mod - b % mod) % mod = (a - b) % mod这意味着:两个数相减再取模的结果,等于它们各自取模后相减,再对差取模的结果。
注意 :由于编程语言中
%运算对负数的处理方式,为确保结果落在[0, mod-1]的非负范围内,当(a % mod - b % mod)为负数时,通常需要加上一个mod进行调整。 -
乘法同余规则
(a % mod) * (b % mod) % mod = (a * b) % mod这意味着:两个数相乘再取模的结果,等于它们各自取模后相乘,再对积取模的结果。
除法同余原理
一、问题引入:为什么不能直接对除法取模?
考虑计算 (10 / 5) % 3。实际结果为:
-
10 / 5 = 2 -
2 % 3 = 2
但如果直接对分子和分母分别取模:
-
10 % 3 = 1 -
5 % 3 = 2 -
(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 的作用。
三、使用乘法逆元的前提条件
要使上述转换成立,必须满足以下三个条件:
-
整除性 :
a / b必须为整数(即a能被b整除)。 -
模数为质数 :
MOD必须是质数(例如常见的1000000007)。 -
互质条件 :
b与MOD必须互质(即最大公约数为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:
-
计算
5的逆元:inv(5) = 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
这样,即使 a 和 b 很大,我们也可以安全地计算。
六、关于指数运算的说明
你可能会担心 b^(MOD-2) 的指数很大(例如 MOD=1000000007)。实际上,我们可以通过快速幂算法 在 O(log MOD) 时间内高效计算,并在计算过程中不断取模,确保不会溢出。
七、总结与记忆要点
当题目满足以下条件时:
-
需要计算
(a / b) % MOD -
MOD是质数(如1000000007) -
b与MOD互质 -
a能被b整除
我们可以按以下步骤计算:
-
计算
b的逆元:inv(b) = b^(MOD-2) % MOD -
计算最终结果:
(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);
}
