轉自:https://blog.csdn.net/LOOKQAQ/article/details/81282342
【同余的定義】:

【同余的主要性質】:
(a+b)%d=(a%d+b%d)%d
加減乘除都能分開寫
要注意的是減法,因為減法可能會減出來負值所以可以這樣寫(a-b+mod)%mod;
性質證明:

【逆元】
(1)定義:
就是一個數的倒數,那為什么要求一個數的倒數:比如a/b這個時候b的值特別大,就是導致double精度不夠所以我們要將a/b換成a*c,其中c^-1=b.

【費馬小引理求解逆元】:(易知費馬定理是有限制的:a與p要互質)

代碼實現:(精華就是快速冪)
1 long long quickpow(long long a,long long b){ 2 if(b<0) return 0; 3 long long ret=1; 4 a%=mod; 5 while(b){ 6 if(b & 1 ) ret = ( ret *a ) % mod 7 b>>=1; 8 a = (a * a)% mod; 9 } 10 return ret; 11 } 12 long long inv(long long a){ 13 return quickpow(a,mod-2); 14 }
【擴展歐幾里得算法求逆元】:

輾轉相除法:
可以來這看看(回溯得到方程解):https://baike.baidu.com/item/輾轉相除法/4625352?fr=aladdin#4
(2)擴展歐幾里得算法的證明:(這種方法也要求a和m互質)

(3)求解逆元:

(4)代碼實現:
1 #include <iostream> 2 #include <stdio.h> 3 #include <stdlib.h> 4 #include <ctype.h> 5 #include<string.h> 6 #include <math.h> 7 #include<algorithm> 8 using namespace std; 9 typedef long long ll; 10 void extgcd(ll a,ll b,ll& d,ll& x,ll& y) 11 { 12 if(!b) 13 { 14 d=a; 15 x=1; 16 y=0; 17 } 18 else 19 { 20 extgcd(b,a%b,d,y,x); 21 y-=x*(a/b); 22 } 23 } 24 int ModularInverse(int a,int b) 25 { 26 27 ll d,x,y; 28 extgcd(a,b,d,x,y); 29 return d==1?(x+b)%b:-1; //返回的結果就是(1/a)mod(b)的結果 30 // complete this part 31 } 32 int main() 33 { 34 printf("%d\n",ModularInverse(2,3));//結果是2 35 /* 36 2*x+3*y=1mod(3) //那個x就是(1/2)mod(3)的結果,y的話不用管,因為3*y取模於3都是0 37 */ 38 return 0; 39 }
(3)、
但是對於要求好多數的逆元的題目,這樣寫會超時
我們還有線性求逆元的方法
來看帶余除法 式子 p=k*i+r
我們可以寫成 k*i+r≡0(mod p)
式子兩邊同乘 i-1*r-1 (i-1,r-1皆為模p意義下的逆元)
所以我們有 k*r-1+i-1≡0(mod p)
i-1≡-k*r-1(mod p)
i-1≡-(p/i)*(p%i)-1(mod p)
所以i-1可以用(p%i)-1推出,所以就可以用遞推式求出來1到i之間所有數的逆元
代碼:
1 //1、線性求逆元 2 int inv[MAXN]; 3 void INV(int a,int p)//線性求到a的逆元 4 { 5 inv[1] = 1; 6 for (int i=2; i<=a; ++i) 7 inv[i] = (-(p/i))*inv[p%i]%p; 8 } 9 10 //2、單獨求某個值的逆元 11 int INV(int a)//線性求a的逆元 12 { 13 if (a==1) return 1; 14 return ((-(p/a)*INV(p%a))%p); 15 }