逆元的意義及求法


逆元的意義:

通俗的講,逆元可以看做一個數的倒數的整數形式,但是一個數的逆元在不同的 $ (mod) $ 意義下是不一樣的。

$ a\times x\equiv1 \mod n \quad $ ☞ $ \quad a\times \frac{1}{a}\equiv1 \mod n $

這個方程便是逆元的真正定義, $ x $ 的解即代表 $ a $ 在 $ \mod n $ 意義下的逆元,通俗的講:此時的 $ x $ 就相當於 $ a $ 的倒數,這樣 $ a\times x $ 便會等於1,在 $ \mod n $ 意義下余數必定為一。當然這個式子要建立在 $ a $ 與 $ n $ 互質的基礎上!

可是逆元有什么用呢?直接用倒數不行嗎?這是因為我們發現一個分數 $ mod $ 一個整數時是不能直接模運算的,但是可以進行乘法運算,我們就要用到逆元(一個數倒數的整數形式)

就像: $ \frac{a}{b}\mod (n) $ $ \not = $ $ \frac{a\mod n}{b\mod n}\mod (n) $ 但是: $ \frac{a}{b}\mod (n) $ $ = $ $ a\times b^{-1}\mod (n) $

所以當除運算碰上我們的模運算時,我們就需要 $ \mod 模數 $ 意義下的逆元了!

單個逆元的求法:

1. 費馬小定理:

對於整數 $ a $ 與質數 $ p $ ,若 $ a $ 與 $ p $ 互質,則有: $ a^{p-1}\equiv1 \mod p $

我們將上述定理稍稍變一下: $ a\times a^{p-2}\equiv1 \mod p $ (這不就是我們的逆元定義式嗎?)

所以 $ a^{p-2} $ 就是 $ a $ 在 $ \mod p $ 意義下的逆元啊!這個我們用快速冪求一下不就行了嗎!

inline ll fast(ll x){//求x在%mod意義下的逆元
	int y=mod-2;ll res=1;
	while(y){
		if(y&1)res=res*x%mod;
		x=x*x%mod; y>>=1;
	}return res;
}

2. 拓展歐幾里得:

用快速冪求逆元,是敵不過某些毒瘤出題人,比如模數就是個long long,這樣快速冪就會溢出。這個時候怎么辦?嗯,我們的萬能 $ gcd $ 就要登場了!(請不要理會博主的中二病,然后防爆longlong還可以用快速乘的

  1. 存在整數 $ x_1 $ 和 $ y_1 $ ,使得: $ x_1\times a+y_1\times b=gcd(a,b) $
  2. 同理,存在整數 $ x_2 $ 和 $ y_2 $ ,使得: $ x_2\times b+y_2\times (a\mod b) =gcd(b,a\mod b) $

根據我們萬能 $ gcd $ 的性質,上述兩個等式的右半部分相同,同理它們的左半部分也相同!

於是我們得到:

  1. $ x_1\times a+y_1\times b=x_2\times b+y_2\times (a\mod b) $
  2. $ x_1\times a+y_1\times b=x_2\times b+y_2\times (a-\frac{a}{b}\times b) $
  3. $ x_1\times a+y_1\times b=y_2\times a+(x_2-y_2\times \frac{a}{b})\times b $
  4. $ x_1=y_2 \quad $ $ \quad y_1=x_2-y_2\times \frac{a}{b} $

所以我們根據 $ x_2 $ 和 $ y_2 $ 就能求出 $ x_1 $ 和 $ y_1 $ 辣!而眾所周知的,我們 $ gcd $ 大法的終極形態就是當 $ b0 $ 的時候,這時我們的 $ x=1 $ ,而因為 $ b0 $ ,所以我們的 $ y $ 隨便取一個就行(好像都用0的),然后我們在回溯的時候,不斷往前推我們的 $ x $ 和 $ y $ ,直到得出我們最初的哪一組解。(這其實就是一個構造的過程)

可是這和求逆元又有什么聯系呢?我們發現只有當我們的 $ a $ 與 $ b $ 互質的時候即 $ gcd(a,b)=1 $ 時,這個二元一次方程不就變成了: $ x_1\times a+y_1\times b=1 $ (等同於 $ x_1\times a=1(\mod b) $ 或 $ y_1\times b=1(\mod a) $ )而這,不就相當於我們逆元的定義式嗎?我們再用上述方法將 $ x_1 $ 和 $ y_1 $ 求出來,不就是逆元了嗎?

inline int exgcd(int a,int b,int &x,int &y){
	if(b==0)return x=1,y=0,a;
	int d=exgcd(b,a%b,y,x);
	y-=(a/b)*x; return d;
}

遞推求多個逆元:

上面我們說的是單個求逆元的方法,復雜度為 $ O(logn) $ 級別(一般快速冪要快一些),可是有一些題目往往需要我們求多個逆元(如連續的數,階乘,和次方的逆元),而且單個求的時間往往要在 $ O(1) $ 的復雜度,我們有沒有辦法 $ O(n) $ 求出所有這些逆元呢?答案是可以的,但只能是一些特殊的數。

線性求逆元:

同余是神奇的,我們可以通過它推出一個逆元的遞推式:

$ \Rightarrow inv[i]=(m-m/i)\times inv[m \mod i] \mod m $

推導過程:設 $ a=m/i $ ,設 $ b=m \mod i $ ,則有 $ m=a\times i+b $

$ \Rightarrow a\times i+b\equiv 0\mod(m) $

$ \Rightarrow -a\times i\equiv b\mod(m) $

我們將同余號兩邊都除以一個 $ i\times b $ ,把逆元這個概念引進來,得到:

$ \Rightarrow -a\times inv[b]\equiv inv[i]\mod(m) $

這樣,我們就將 $ i $ 和 $ m \mod i $ 聯系到了一起,我們將 $ a $ 和 $ b $ 換回原裝可得:

$ \Rightarrow -m/i\times inv[m \mod i]\equiv inv[i]\mod(m) $

$ \Rightarrow inv[i]\equiv (m-m/i)\times inv[m \mod i] \mod(m) $

$ \Rightarrow inv[i]=(m-m/i)\times inv[m \mod i] \mod m $

這樣,只要我們預處理一下 $ inv[1]=1 $ ,往后的所有逆元我們都能線性求了!

int main(){
    n=qr(),m=qr(); inv[1]=1;
    for(int i=2;i<=n;i++)
        inv[i]=(ll)(m-m/i)*inv[m%i]%m;
    return 0;
}

線性求階乘逆元: (這個比上面的要簡單一些。)

我們都知道,階乘代表: $ n!=1\times 2\times 3...\times n $ ,那么我們可以得出: $ (n-1)!=n!/n $

這不也是一個逆元式嗎?只不過我們要倒着遞推而已。

我們先用快速冪或拓展歐幾里得求出 $ n! $ 的逆元,然后所有比它小的逆元都可以線性推過去了!

int main(){
    n=qr(),m=qr(); jc_inv[n]=1;
    for(int i=n;i>=2;--i)
        jc_inv[i-1]=(ll)jc_inv[i]*i%m;
    return 0;
}


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM