逆元:
定義:正の整数aの場合、ax≡1(mod m)がある場合、ここでの等号は恒等式を表すことに注意してください。この合同方程式の最小の正の整数解xは、mod mの逆元と呼ばれます(実際、x * x ^ -1 = 1のバリアントでは同等です。
逆元を見つけるために一般的に使用される3つの方法があります。拡張ユークリッドアルゴリズム、フェルマーの小定理、および逆元を見つけるためのオイラーの定理です。もちろん他の方法もありますが、以下では上記の3つだけを紹介します。
拡張ユークリッドアルゴリズム:
ユークリッドアルゴリズムは2つの数値の最大公約数を返し、拡張ユークリッドアルゴリズムは最大公約数を返しますが、渡すパラメーターはそれだけです。
定義:ax + by = gcd(a、b)(数論の知識に基づいてこの式の解が存在する必要があります)が
一般的に使用されるように、既知のa、bのxとyのセットを解くために使用されますモジュラー線形方程式と方程式グループを解きます。
xとyを解く方法の理解について:方程式ax + by = gcd(a、b)は既知です
(1)b = 0の場合、gcd(a、b)= a、次にx = 1、y = 0; 1 a + 0 b = a
(2)ax1 + by1 = gcd(a、b)とします。
次のexgcdbx2 +(a mod b)y2 = gcd(b、mod b)
Euclidの原理によれば、gcd(a、b)= gcd(b、mod b)、
次にax1 + by1 = bx2 +(a mod b)y2
は、ax1 + by1 = bx2 +(a-(a / b)* b)y2 = ay2 + bx2-(a / b)* by2を意味し、
x1 = y2、y1 = x2-(a / b)y2;
したがって、x1、y1の値はx2、y2に基づいていると結論付けることができます。
コード:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
const int N=200;
char s[N];
char b[N];
int exgcd(int a,int b,int &x,int &y)//扩展gcd
{
if(!b)//b为0的情况
{
x=1;
y=0;
return a;
}
int r=exgcd(b,a%b,x,y);
int t=x;
x=y;
y=t-a/b*y;
return r;
}
int main()
{
ios::sync_with_stdio(false);
int a,b;
cin>>a>>b;
int x=0,y=0;
cout<<exgcd(a,b,x,y)<<endl;
return 0;
}
1.拡張gcd逆元では、aとmが互いに素である必要があります
見つかった逆元は最小の逆元です
まず、互いに素の概念を示します。n個の数(n> = 2)の
公約数は1だけです。素数は素数とも呼ばれます。
最初に数学的プロセスを与えます:
ax + by = gcd(a、b);
次にax + my = gcd(a、m);
aとmは互いに素であるため、gcd(a、m)= 1
、次にax + my = 1
つまり
、この時点でのax≡1(mod m)xはaの逆数です。
コード:拡張gcdを使用してx、y、gcdのセットを検索します。gcdが1の場合、逆元が存在し、xを0〜m-1の範囲に調整します。それ以外の場合、逆元は存在しません。
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
using namespace std;
const int N=200;
char s[N];
char b[N];
int exgcd(int a,int b,int &x,int &y)
{
if(a==0&&b==0)
return -1;
if(!b)
{
x=1;
y=0;
return a;
}
int d=exgcd(b,a%b,y,x); //回代 注意这里的与扩展gcd的不同
y-=a/b*x;
return d;
}
int main()
{
ios::sync_with_stdio(false);
int m,n;
cin>>m>>n;
int x,y;
int d=exgcd(m,n,x,y);
cout<<(x%n+n)%n<<endl;
return 0;
}
2.フェルマーの小定理では、mが素数である必要があり、aとmは互いに素です。
フェルマーの小定理:a ^(m-1)≡1(mod m)// mは素数
a ^(m-1)≡1(mod m)の場合、a * a ^(m-2)≡1( mod m)
したがって、a ^(m-2)は、mを法とする(高速電力で解かれる)
時間計算量logNの逆元です。
コード:
int mod;
int quick_mod(int n,int p)
{
int res=1,k=p;
while(k)
{
if(k%2)
res=res*n%mod;
n=n*n%mod;
k/=2;
}
return res;
}
int main()
{
ios::sync_with_stdio(false);
int a;
cin>>a>>mod;
cout<<quick_mod(a,mod-2)<<endl;
return 0;
}
3.逆元のオイラーの定理:基本的な一般的な
時間計算量lg(√n)。
オイラーの定理:a ^(∅(m))≡1(mod m)
、a * a ^(∅(m)-1)≡1(mod m)
はax≡1(mod m)
なので、a ^(∅( M)-1)はaの逆数です∅(m)はm未満で互いに素な数の数です
1. n = 1の場合、φ(1)= 1です。1と任意の数(それ自体を含む)が互いに素な関係を構成する
ためです。2。素数pΦ(p)= p-1の場合、2つの素数pqの場合、Φ(pq)= pq-1
オイラー関数は乗法関数です。 、しかし、それは完全乗法的関数ではありません
。3。nが素数の特定の累乗である場合、つまりn = p ^ k(pは素数であり、kは1以上の整数)、その後のため
の例示φ(8)=φ(2 ^ 3)= 2 ^ 3-2 ^ 2 = 8 -4 = 4。
これは、数に素数pが含まれていない場合にのみ、nに対して互いに素になることができるためです。そして素数pを含む合計p (k-1)の数、すなわち1×p、2×p、3×p、...、p(k-1)×pがあり、それらを削除し、残りはnは互いに素な数です。
上記の式は、次の形式でも記述
できます。4。nを2つの互いに素な整数、n = p1 * p2の積に分割できる場合
、Φ(n)=Φ(p1)*Φ(p2)
5 。数n(n> 1)は
、結論4に従って、一連の素数として積を記述
し、結論に従ってさらに3を与える
ことができます。
オイラーの数を見つけるための2つのコードを以下に示します。
オイラーに直接尋ねる:
int euler(int x)
{
int res=x;
for(int i=2;i*i<=x;i++)
if(x%i==0)
{
res=res/i*(i-1);
while(x%i==0)
x/=i;
}
if(x>1)
res=res/x*(x-1);
return res;
}
テーブルを直接使用することもできます。プロセスでは、各phi [i] = iを作成し、各素数pについて、jはその倍数です。phi[j] = phi [j] / p *(p-1 );
void eulerplus()
{
for(int i=1;i<=N;i++)
phi[i]=i;
for(int i=2;i<=N;i+=2)
phi[i]/=2;
for(int i=3;i<=N;i+=2)
if(phi[i]==i)
{
for(int j=i;j<=N;j+=i)
phi[j]=phi[j]/i*(i-1);
}
}
4.逆元の適用モジュラ逆元
ax≡1(mod m)
so x = 1 / a(mod m)
so(b / a)mod m
then(b x)mod m
then(b%m )を見つけますx%m)%M
ストライリングフォーミュラ
多くの場合、nを要求するために使用されます!おおよその値
n!≈√2πn(n / e)^ n
エム、写真をアップロードしましょう
このナレッジポイントをlgと組み合わせて使用すると、数値
nの桁数x = logn(x)+ 1、
たとえば10進数の桁数x = lg(x)+1を見積もることができます。
ある数の階乗が別の数の倍数であると推定することもできます。