## 思路 ### 一、前置知识 #### 1、什么是逆元 #### 2、为什么要创造逆元的概念 ### 二、乘法逆元 $A$除以一个数模$P$,等于$A$乘以这个数的乘法逆元模$P$。 $(A/B)\% 9937 = (A*B^{-1}) \%9973$. 这里的$B^{-1}$ 代表乘法逆元,而不是$\frac{1}{B}$. 所以我们只需要求解出$B$对于$9973$的 乘法逆元$B^{-1}$ 即可。 ### 三、解法一:费马小定理求解乘法逆元 只适用于模数为质数的情况 若$a$是一个整数(除法分母),$b$是一个质数(模),那么 $a^b ≡ a(mod \ b)$ 或 $a^{b-1}≡1 (mod\ b)$ 由扩展欧几里得可以得出: 因为$gcd(a,b) = 1, ax ≡ 1(mod \ b)$ $x$是**乘法逆元** $a^{b-1} = a*a^{b-2}= ax ≡1(mod \ b)$. 所以 $x = a^{b-2}$就是乘法逆元。 可以通过快速幂求解。 在本题求$x = a^{9973-2}$。 ```c++ // https://vjudge.csgrandeur.cn/problem/HDU-1576 #include using namespace std; typedef long long LL; /* 测试用例 2 1000 53 87 123456789 答案 7922 6060 总结: 1、如果使用费马小定理+快速幂求逆元,一定要注意使用LL,防止爆int。 */ const int MOD = 9973; LL qmi(LL a, LL k, LL p) { LL res = 1; while (k) { if (k & 1) res = res * a % p; //如果res是int,可能会越界 k >>= 1; a = a * a % p; //如果a是int, 可能会越界 } return res; } int main() { int T; cin >> T; while (T--) { LL a, b; cin >> a >> b; LL x; x = qmi(b, MOD - 2, MOD); // b理解为分母,同余MOD的逆元,变除法为乘法 LL res = a * x % MOD; // a* b在模MOD下的逆元 x printf("%lld\n", res); } return 0; } ``` ### 四、解法二:扩展欧几里得 根据 扩展欧几里得 : 模数可以 不为质数 因为$gcd(B,9973) = 1$,所以 $Bx ≡ 1(mod \ 9973)$, $x$ 是 $B^{-1}$,也就是$B$的乘法逆元 通过`ex_gcd(B,9973)`求出来的`x`就是$B^{-1}$,因为求出来的$x$可能是负数,利用通解所以处理一下 ```C++ x = (x % t + t) % t; ``` 实现代码 ```c++ // https://vjudge.csgrandeur.cn/problem/HDU-1576 #include typedef long long LL; /* 测试用例 2 1000 53 87 123456789 答案 7922 6060 */ using namespace std; const int MOD = 9973; LL exgcd(LL a, LL b, LL &x, LL &y) { if (!b) { x = 1, y = 0; return a; } LL d = exgcd(b, a % b, y, x); y -= a / b * x; return d; } int main() { int t; cin >> t; while (t--) { LL x, y; LL a, b; cin >> a >> b; exgcd(b, MOD, x, y); x = (x % MOD + MOD) % MOD; //对比使用费马小定理,这里对于扩展欧几里得算出的逆元,还需要进一步模一下 MOD才行,否则可能是负的 cout << (x * a) % MOD << endl; } return 0; } ```