原题链接:
题解:
Fermat费马小定理:
已知b * x ≡ 1 (mod n),x是b的逆元
由费马小定理可知,当n为质数时
b ^ (n - 1) ≡ 1 (mod n)
拆一个b出来可得 b * b ^ (n - 2) ≡ 1 (mod n)
故当n为质数时,b的乘法逆元 x = b ^ (n - 2)
Euclid拓展欧几里得:
拓展欧几里得算法可用于任意情况(n为素数或者合数都可以)
a有逆元的充要条件是a与p互质,所以gcd(a, p) = 1
假设a的逆元为x,那么有a * x ≡ 1 (mod p)
等价:ax + py = 1 = gcd(a,p)
exgcd(a, p, x, y)证明:
当 b=0 时,gcd(a,b)=a,此时 x=1 , y=0
当 b!=0 时,
设 ax1+by1=gcd(a,b)=gcd(b,a%b)=bx2+(a%b)y2
又因 a%b=a-a/b*b
则 ax1+by1=bx2+(a-a/b*b)y2
ax1+by1=bx2+ay2-a/b*by2
ax1+by1=ay2+bx2-b*a/b*y2
ax1+by1=ay2+b(x2-a/b*y2)
解得 x1=y2 , y1=x2-a/b*y2
因为当 b=0 时存在 x , y 为最后一组解
而每一组的解可根据后一组得到
所以第一组的解 x , y 必然存在
- 根据上面的证明,在实现的时候采用递归做法
- 先递归进入下一层,等到到达最后一层即 b=0 时就返回x=1 , y=0
- 再根据 x1=y2 , y1=x2-a/b*y2 ( x2 与 y2 为下一层的 x 与 y ) 得到当层的解
- 不断算出当层的解并返回,最终返回至第一层,得到原解
代码:
Fermat费马小定理:
#include<bits/stdc++.h>
using namespace std;
using ULL = unsigned long long;
//费马小定理——适合求解p为素数的情况
ULL qmi(ULL a, ULL b, ULL c) {
ULL res = 1;
while (b) {
if (b & 1) res = res * a % c;
b >>= 1;
a = a * a % c;
}
return res;
}
int main() {
int n;cin >> n;
while (n--) {
int a, b;cin >> a >> b;
if (a % b == 0) cout << "impossible" << endl;
else cout << qmi(a, b - 2, b) << endl;
}
}
Euclid拓展欧几里得:
#include <iostream>
using namespace std;
typedef long long LL;
int n;
int exgcd(LL a, LL b, LL& x, LL& y)
{
if (!b) {
x = 1, y = 0;
return a;
}
int d = exgcd(b, a % b, y, x);
y -= a / b * x;
return d;
}
int main()
{
cin >> n;
while (n--)
{
LL a, p, x, y;
cin >> a >> p;
int d = exgcd(a, p, x, y);
if (d == 1) cout << (x + p) % p << endl;//保证x是正数
else cout << "impossible" << endl;
}
}