逆元を学ぶ(拡張ユークリッド、フェイシャオマの定理、線形解)

逆元:方程式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

 

おすすめ

転載: blog.csdn.net/qq_44132777/article/details/107347619