123 lines
3.0 KiB
Markdown
123 lines
3.0 KiB
Markdown
|
|
## 思路
|
|||
|
|
|
|||
|
|
### 一、前置知识
|
|||
|
|
|
|||
|
|
#### 1、什么是逆元
|
|||
|
|
|
|||
|
|
#### 2、为什么要创造逆元的概念
|
|||
|
|
|
|||
|
|
|
|||
|
|
### 二、乘法逆元
|
|||
|
|
$A$除以一个数模$P$,等于$A$乘以这个数的乘法逆元模$P$。
|
|||
|
|
|
|||
|
|
$(A/B)\% 9937 = (A*B^{-1}) \%9973$. 这里的$B^{-1}$ 代表乘法逆元,而不是$\frac{1}{B}$.
|
|||
|
|
|
|||
|
|
所以我们只需要求解出$B$对于$9973$的 <font color='red'><b>乘法逆元$B^{-1}$</b></font> 即可。
|
|||
|
|
|
|||
|
|
|
|||
|
|
### 三、解法一:费马小定理求解乘法逆元
|
|||
|
|
<font color='red'><b>只适用于模数为质数的情况</b></font>
|
|||
|
|
|
|||
|
|
若$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 <bits/stdc++.h>
|
|||
|
|
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;
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 四、解法二:扩展欧几里得
|
|||
|
|
<font color='red'><b>根据 扩展欧几里得 : 模数可以 不为质数</b></font>
|
|||
|
|
|
|||
|
|
因为$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 <bits/stdc++.h>
|
|||
|
|
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;
|
|||
|
|
}
|
|||
|
|
```
|