逆元:方程式ax≡1(modn)の解x。これはモジュロmの逆数と呼ばれます。
逆元の重要な用途は、除算の係数を見つけることです。
たとえば、(a / b)%m =?
bの逆元がkであるとすると、(a / b)%m =((a / b)%m)((bk)%m)=(a / b * bk)%m =(ak)%m
したがって、(a / b)%mの値を見つけることは、bの逆元を見つけることと同じです。
逆元を見つけるためのいくつかの方法:
1.拡張ユークリッドアルゴリズム
方程式ax≡1(modm)を解くことは、ax + my = 1を解くことと同等です(ax-1はmの整数倍であり、yを倍数とすると、ax-1 = my、つまりax + my = 1、yは負になる可能性があります);
解ける条件は次のとおりです。gcd(a、m)= 1、つまり、aとmは互いに素です。
void extend_gcd(int a,int b,int &x,int &y) {
if(b==0) {
x=1,y=0;
return;
}
extend_gcd(b,a%b,x,y);
int tmp=x;
x=y;
y=tmp-(a/b)*y;
}
int mod_inverse(int a,int m) {
int x,y;
extend_gcd(a,m,x,y);
return(m+x%m)%m; //x可能是负数,需要处理
}
2.フェルマーの小定理
ましょmが素数であると%M≠0、次いで^(M-1)≡1(MOD M)。
次に、a * a ^(m-2)≡1(mod m)の場合、その逆数はa ^(m-2)です。逆元は高速で解くことができます
typedef long long ll;
ll quick_pow(ll b, ll n) {
ll ans = 1, po = b;
while(n) {
if(n & 1) ans = (ans * po) % mod;
po = (po * po) % mod;
n >>= 1;
}
return ans;
}
3.逆元を線形に解きます
法素数pの下で、1〜nの逆元n <pを見つけます。すべての逆関数はO(n)にあります。
假設定p = k * i + j、(1 <i <p、j <i)
p = k ∗ i +j≡0(modp)であることがわかります。
両側に(ij)^(-1)を掛けて、i ^(-1)+ k * j ^(-1)= 0を取得します。
その場合、変化はi ^(-1)=-k * j ^(-1)になります (1 / iはiの逆元であり、1 / jはjの逆元です)
そして、1 ^(-1)≡1(mod p)
したがって、再発a [i] =-(p / i)* a [p%i]を取得できます。
a [1] = 1
さらに:1-> pを法とするpのすべての逆元値は、1-> pのすべての数値に対応します(たとえば、p = 7)。その場合、1-> 6に対応する逆元は14 5 2 36です。
void inverse(int n, int p) {
a[1] = 1;
for (int i=2; i<=n; ++i) {
a[i] = (ll) (p - p / i) * a[p%i] % p;
}
}
参照リンク:https://blog.csdn.net/guhaiteng/article/details/52123385
https://www.cnblogs.com/lifehappy/p/12763635.html