乘法逆元及其应用(一)

最近学会了乘法逆元,有做了几道题,才发现乘法逆元在有除法又要取模的题目中非常有用。

乘法逆元

1.定义
若整数 b , m b,m b,m互质,并且 b ∣ a b|a ba,则存在一个整数 x x x,使得 a / b ≡ a ∗ x ( m o d m ) a/b \equiv a*x \pmod{m} a/bax(modm)。称 x x x b b b的模m乘法逆元,记为 b − 1 ( m o d m ) b^{-1}\pmod{m} b1(modm)

2.证明
因为 a / b ≡ a ∗ b − 1 ≡ a / b ∗ b ∗ b − 1 ( m o d m ) a/b \equiv a*b^{-1} \equiv a/b*b*b^{-1} \pmod{m} a/bab1a/bbb1(modm),所以 b ∗ b − 1 ≡ 1 ( m o d m ) b*b^{-1} \equiv 1 \pmod{m} bb11(modm)
如果 m m m是质数(此时我们用符号 p p p代替 m m m)并且 b < p b<p b<p,根据费马小定理, b p − 1 ≡ 1 ( m o d p ) b^{p-1} \equiv 1 \pmod{p} bp11(modp),即 b ∗ b p − 2 ≡ 1 ( m o d p ) b*b^{p-2} \equiv 1 \pmod{p} bbp21(modp)。因此,当模数p为质数时, b p − 2 b^{p-2} bp2即为 b b b的乘法逆元

3.用处
有了乘法逆元,在遇到有 a / b a/b a/b的计数类问题中,只需要求出乘法元,然后直接 a ∗ x a*x ax即可。

乘法逆元的应用

给一道题
POJ1845
题目描述
【题意】
Consider two natural numbers A and B. Let S be the sum of all natural divisors of A^B. Determine S modulo 9901 (the rest of the division of S by 9901).
题目关于两个自然数A和B。S是所有A^B的自然数因子的和。输出S模以9901(就是S除以9901的余数)

【输入格式】
The only line contains the two natural numbers A and B, (0 <= A,B <= 50000000)separated by blanks.
只有一行,两个用空格隔开的自然数A和B(0<=A,B<=50000000)

【输出格式】
The only line of the output will contain S modulo 9901.
只有一行,S模以9901

【样例输入】
2 3

【样例输出】
15

【提示】
2^3 = 8.
The natural divisors of 8 are: 1,2,4,8. Their sum is 15.
15 modulo 9901 is 15 (that should be output).
8的自然数因子有:1,2,4,8。它们的和是15。
15模以9901就是15。

我们直接分解A的质因数,表示为 A = p 1 c 1 ∗ p 2 c 2 ∗ . . . ∗ p n c n A=p_1^{c_1}*p_2^{c_2}*...*p_n^{c_n} A=p1c1p2c2...pncn。所以 A B A^B AB的所有约数之和为: ( 1 + p 1 + p 1 2 + . . . + p 1 B ∗ c 1 ) ∗ ( 1 + p 2 + p 2 2 + . . . + p 2 B ∗ c 2 ) ∗ . . . ∗ ( 1 + p 3 + p 3 2 + . . . + p 3 B ∗ c 3 ) (1+p_1+p_1^2+...+p_1^{B*c_1})*(1+p_2+p_2^2+...+p_2^{B*c_2})*...*(1+p_3+p_3^2+...+p_3^{B*c_3}) (1+p1+p12+...+p1Bc1)(1+p2+p22+...+p2Bc2)...(1+p3+p32+...+p3Bc3)
上式的每一项都是一个等比数列。以第一项为例, ( 1 + p 1 + p 1 2 + . . . + p 1 B ∗ c 1 ) = ( p 1 B ∗ c 1 + 1 − 1 ) / ( p 1 − 1 ) (1+p_1+p_1^2+...+p_1^{B*c_1})=(p_1^{B*c_1+1}-1)/(p_1-1) (1+p1+p12+...+p1Bc1)=(p1Bc1+11)/(p11)
发一波等比数列求和的推导公式
在这里插入图片描述
所以我们可以先用快速幂计算分子 ( p 1 B ∗ c 1 + 1 − 1 ) m o d    9901 (p_1^{B*c_1+1}-1) \mod 9901 (p1Bc1+11)mod9901 和分母 ( p 1 − 1 ) m o d    9901 (p_1-1)\mod9901 (p11)mod9901。因为9901时质数,只要 p 1 − 1 p_1-1 p11不是9901的倍数,就只需要计算 p 1 − 1 p_1-1 p11的乘法逆元 i n v inv inv,用乘 i n f inf inf代替除以 ( p 1 − 1 ) (p_1-1) (p11),直接计算出等比数列求和公式的结果。
特别的,若 p 1 − 1 p_1-1 p11是9901的倍数,此时乘法逆元不存在,但是 p 1 m o d    9901 = 1 p_1\mod 9901=1 p1mod9901=1,所以 1 + p 1 + p 1 2 + . . . + p 1 B ∗ c 1 ≡ 1 + 1 + 1 2 + . . . + 1 B ∗ c 1 ( m o d 9901 ) 1+p_1+p_1^2+...+p_1^{B*c_1} \equiv 1+1+1^2+...+1^{B*c_1} \pmod{9901} 1+p1+p12+...+p1Bc11+1+12+...+1Bc1(mod9901)

参考代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
int a, b, m, ans = 1, mod = 9901;
int p[20], c[20];

void divide(int n) {
    m = 0;
    for (int i = 2; i * i <= n; i++) {
        if (n % i == 0) {
            p[++m] = i, c[m] = 0;
            while (n % i == 0) n /= i, c[m]++;
        }
    }
    if (n > 1)
        p[++m] = n, c[m] = 1;
}

int power(int a, long long b) {
	int c = 1;
	for (; b; b >>= 1) {
		if (b & 1) c = (long long)c * a % mod;
		a = (long long) a * a % mod;
	}
	return c;
}

int main() {
	cin >> a >> b;
	divide(a); // 分解质因数 
	for (int i = 1; i <= m; i++) {
		if ((p[i] - 1) % mod == 0) { // 没有逆元时,特判 
			ans = ((long long)b * c[i] + 1) % mod * ans % mod;
			continue;
		}
		int x = power(p[i], (long long)b * c[i] + 1); // 分子
		x = (x - 1 + mod) % mod;
		int y = p[i] - 1; // 分母 
		y = power(y, mod - 2); // 根据费马小定理求乘法逆元
		ans = (long long)ans * x % mod * y % mod;
	}
	cout << ans <<endl;
}
### 关于乘法逆元的定义与性质 在模 \( p \) 的意义下,如果存在整数 \( x \),使得 \( a \cdot x \equiv 1 \ (\text{mod} \ p) \),则称 \( x \) 是 \( a \) 模 \( p \)乘法逆元[^1]。然而,只有当 \( a \) 和 \( p \) 互质时,\( a \) 才可能有模 \( p \) 下的乘法逆元[^3]。 对于 \( a \) 和 \( p \) 不互质的情况,即 \( \gcd(a, p) > 1 \),不存在这样的 \( x \) 能够满足上述条件。这是因为根据扩展欧几里得算法,寻找乘法逆元的过程本质上是在解线性同余方程: \[ a \cdot x + p \cdot y = 1 \] 其中 \( x \) 即为所求的乘法逆元。而该方程是否有解取决于 \( \gcd(a, p) \) 是否能够整除常数项 1。显然,当 \( \gcd(a, p) > 1 \) 时,此方程无解,因此无法找到对应的乘法逆元[^2]。 ### 特殊情况下的替代方案 尽管如此,在某些特定场景中仍可采用其他方式来模拟或近似实现类似于“乘法逆元”的功能。以下是几种常见的思路: #### 方法:通过分数表示代替直接求逆元 如果目标是为了完成某种形式上的“除法”,可以通过引入额外变量或者转换成分数的形式间接表达结果。例如给定两个数 \( b \) 和 \( c \),希望计算 \( (b / c) \% p \),即使 \( c \) 和 \( p \) 并非互素关系,也可以改写为如下形式: \[ (b / c) \% p = ((b \% p) \times d^{-1}) \% p, \] 这里 \( d^{-1} \) 表达的是某个适当选取数值作为伪逆元的角色。具体操作需视实际应用需求调整[^4]。 #### 方法二:利用中国剩余定理(CRT) 假设已知多个不同的模数及其对应条件下各自的乘法逆元,则可通过CRT组合这些局部信息得到全局解决方案。这种方法特别适用于多组数据联合分析的情形之下。 ```python from sympy import mod_inverse def crt_modular_inverse(a_list, m_list): """ 使用 CRT 计算整体意义上的 '伪' 乘法逆元 """ total_product = 1 result = 0 for mi in m_list: total_product *= mi for ai, mi in zip(a_list, m_list): pi = total_product // mi yi = mod_inverse(pi % mi, mi) result += ai * pi * yi return result % total_product # 示例调用 print(crt_modular_inverse([4], [7])) # 输出应接近原问题中的简单情形 ``` 注意以上代码片段仅为示意用途,并未完全覆盖所有边界状况;真实项目开发前还需进步验证完善逻辑正确性和鲁棒性表现。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值