标签:扩展欧几里得 ret 效率 适用于 == gcd int exgcd 算法
一、快速幂求逆元
1、直接用费马小定理 $a^{(p - 1)}\equiv 1(mod m) < = > a^{(p - 2)}\equiv a^{-1}(mod m)$ 当m为素数时
2、当m不为素数时 已知m的欧拉函数满足 $a^{\phi (m)}\equiv 1(mod m) < = > a^{\phi (m) - 1}\equiv a^{-1}(mod m)$
所以可以直接 用$a^{\phi (m) - 1}\equiv a^{-1}(mod m)$
先用gcd判断a和m是否互质 若不互质 则不存在模m下的逆元
int prime[maxn+10], phi[maxn+10]; bool vis[maxn+10]; int ans; void get_phi() { ans = 0; phi[1] = 1; for(int i=2; i<=maxn; i++) { if(!vis[i]) { prime[++ans] = i; phi[i] = i - 1; } for(int j=1; j<=ans; j++) { if(i * prime[j] > maxn) break; vis[i * prime[j]] = 1; if(i % prime[j] == 0) { phi[i * prime[j]] = phi[i] * prime[j]; break; } else phi[i * prime[j]] = phi[i] * (prime[j] - 1); } } } LL q_pow(LL a, LL b, LL M) { LL res = 1; while(b) { if(b & 1) res = res * a % M; a = a * a % M; b >>= 1; } return res; } LL gcd(LL a, LL b) { return b == 0 ? a : gcd(b, a % b); } int main() { get_phi(); int T; rd(T); while(T--) { LL n, m; cin >> n >> m; if(gcd(n, m) != 1) cout << "Not Exist" << endl; else { int d = q_pow(n, phi[m] - 1, m); cout << d << endl; } } return 0; }
二、exgcd求逆元
给定模数m,求a的逆相当于求解ax=1(mod m)
这个方程可以转化为ax-my=1
然后套用求二元一次方程的方法,用扩展欧几里得算法求得一组x0,y0和gcd
检查gcd是否为1
gcd不为1则说明逆元不存在
若为1(a与m互质),则调整x0到0~m-1的范围中即可
PS:这种算法效率较高,常数较小,时间复杂度为O(ln n)
适用范围:只要存在逆元即可求,适用于个数不多但是mod很大的时候,也是最常见的一种求逆元的方法。
void extgcd(ll a,ll b,ll& d,ll& x,ll& y) { if(!b) { d=a; x=1; y=0;} else { extgcd(b,a%b,d,y,x); y-=x*(a/b); } } void inverse(ll a,ll n) { ll d,x,y; extgcd(a,n,d,x,y); if(d == 1) { x = (x % n + n) % n; if(x == 0) x += n; cout << x << endl; } else //不存在 cout << "Not Exist" << endl; }
标签:扩展欧几里得 ret 效率 适用于 == gcd int exgcd 算法
原文地址:https://www.cnblogs.com/WTSRUVF/p/10805619.html