求逆元基本方法


乘法逆元小結

乘法逆元,一般用於求

$\frac{a}{b} \pmod p$

的值($p$ 通常為質數),是解決模意義下分數數值的必要手段。

一、逆元定義

若$a*x\equiv1 \pmod b$,且$a$與$b$互質,那么我們就能定義: $x$ 為 $a$ 的逆元,記為$a^{-1}$,所以我們也可以稱 $x$ 為 $a$ 在$\mod b$意義下的倒數,

所以對於 $\displaystyle\frac{a}{b} \pmod p$ ,我們就可以求出 $b$ 在 $\bmod p$ 下的逆元,然后乘上 $a$ ,再 $\bmod p$,就是這個分數的值了。

二、求解逆元的方式

1.拓展歐幾里得

條件 $a \bot p$(互質),但 $p$ 不是質數的時候也可以使用。

這個方法十分容易理解,而且對於單個查找效率似乎也還不錯,比后面要介紹的大部分方法都要快(尤其對於 $\bmod p$ 比較大的時候)。

這個就是利用拓歐求解 線性同余方程 $a*x\equiv c\pmod{b}$ 的$c=1$的情況。我們就可以轉化為解 $a*x + b*y = 1$ 這個方程。

引理:$ax+by=c$有解的充分條件是$\gcd(a,b)\mid c$

所以$ax+by=gcd(a,b)①$顯然有解

引理:$gcd(a,b)=gcd(b,a mod b)②$

將$①$代入$②$得

$ax_1+by_1=bx_2+(a mod b)y_2$
$ax_1+by_1=bx_2+(a-[\frac{a}{b}]*b)y_2$
$ax_1+by_1=bx_2+ay-[\frac{a}{b}]*by_2$
$ax_1+by_1=ay_2+b(x_2-[\frac{a}{b}])$

$∴x_1=y_2,y_1=x_2-[\frac{a}{b}]y$

$∵a\bot b$

$∴gcd(a,b)=1$

$∴當b=0時,a=1,此時有x=1,y的最小自然數解為0$

 

代碼比較簡單:

void Exgcd(ll a, ll b, ll &x, ll &y) {
    if (!b) x = 1, y = 0;
    else Exgcd(b, a % b, y, x), y -= a / b * x;
}
int main() {
    ll x, y;
    Exgcd (a, p, x, y);
    x = (x % p + p) % p;
    printf ("%d\n", x); //x是a在mod p下的逆元
}

2.小費爾馬定理(快速冪)

費馬小定理:

若$p$為素數,$a$為正整數,且$a$、$p$互質。 則有$a^{p-1} \equiv 1 (\bmod p)$。

這個我們就可以發現它這個式子右邊剛好為 $1$ 。

所以我們就可以放入原式,就可以得到:

$a*x\equiv 1 \pmod p$

$a*x\equiv a^{p-1} \pmod p$

$x \equiv a^{p-2} \pmod p$

所以我們可以用快速冪來算出 $a^{p-2} \pmod p$的值,這個數就是它的逆元了

代碼也很簡單:

ll fpm(ll x, ll power, ll mod) {
    x %= mod;
    ll ans = 1;
    for (; power; power >>= 1, (x *= x) %= mod)
        if(power & 1) (ans *= x) %= mod;
    return ans;
}
int main() {
    ll x = fpm(a, p - 2, p); //x為a在mod p意義下的逆元
}

 

3.線性推逆元

用於求一連串數字對於一個$\bmod p$的逆元。洛谷P3811

只能用這種方法,別的算法都比這些要求一串要慢。

首先我們有一個,$1^{-1}\equiv 1 \pmod p$

然后設 $p=k*i+r,(1<r<i<p)$ 也就是 $k$ 是 $p / i$ 的商,$r$ 是余數 。

再將這個式子放到$\pmod p$意義下就會得到:

$k*i+r \equiv 0 \pmod p$

然后乘上$i^{-1}$,$r^{-1}$就可以得到:

$k*r^{-1}+i^{-1}\equiv 0 \pmod p$

$i^{-1}\equiv -k*r^{-1} \pmod p$

$i^{-1}\equiv -\lfloor \frac{p}{i} \rfloor*(p \bmod i)^{-1} \pmod p$

於是,我們就可以從前面推出當前的逆元了。

代碼也很短:

inv[1] = 1;
for(int i = 2; i < p; ++ i)
    inv[i] = (p - p / i) * inv[p % i] % p;

 

4.階乘逆元 $O(n)$ 求

因為有如下一個遞推關系。

$\displaystyle inv[i+1]=\frac{1}{(i+1)!}$

$\displaystyle inv[i+1]*(i+1)=\frac{1}{i!}=inv[i]$

所以我們可以求出$n!$的逆元,然后逆推,就可以求出$1...n!$所有的逆元了。

遞推式為

$inv[i+1]*(i+1)=inv[i]$

所以我們可以求出 $\displaystyle \forall i, i!,\frac{1}{i!}$ 的取值了。

然后這個也可以導出 $\displaystyle \frac{1}{i} \pmod p$ 的取值,也就是

$\displaystyle \frac{1}{i!} \times(i-1)!=\frac{1}{i} \pmod p$

如果我們需要求 $0!$ 到 $n!$ 的逆元,對於每個元素都求一遍,就顯得有點慢。

逆元可以看作是求倒數。那么不就有 

$\displaystyle \frac{1}{(n+1)!} \times(n+1)=\frac{1}{n!} \pmod p$

int inv( int b, int p ) {
    int a, k;
    exPower( b, p, a, k );
    if( a < 0 ) a += p;
    return a;
}
void init( int n ) {
    Fact[ 0 ] = 1;
    for( int i = 1; i <= n; ++i ) Fact[ i ] = Fact[ i - 1 ] * i % Mod;
    INV[ n ] = inv( Fact[ n ], Mod );
    for( int i = n - 1; i >= 0; --i ) INV[ i ] = INV[ i + 1 ] * ( i + 1 ) % Mod;
    return;
}

 

三、不存在逆元

當$\gcd(a,p)!=1$時,$a^{-1}\equiv 0\mod p$

當數和模數不互質時,不存在逆元,做題時要特判沒有逆元的情況。

 


免責聲明!

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



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