數論——乘法逆元(快速冪求法)及模運算


一、快速冪

原理:

  快速冪的原理十分簡單。

  ak=a2^0*a2^1*a2^2*…a2^x,其中k=20+21+22+…+2x

  這顯然是正確的。因為任何一個數都可以表示成二進制。

  接下去利用位運算實現即可。

代碼實現

  模板題鏈接:快速冪

  代碼模板如下:時間復雜度O(logk)

int qmi(int a,int k,int p)
{
    int res=1%p;
    while(k)
    {
        if(k&1)res=(long long)res*a%p;
        a=(long long)a*a%p;
        k>>=1;
    }
    return res;
}

  值得一提的是,以上代碼在過程中取模,是基於模運算的運算規則。

  模運算有一些很好的性質,以下列舉四條:

  •  (a + b) % p = (a % p + b % p) % p 
  •  (a - b) % p = (a % p - b % p + p) % p 
  •  (a * b) % p = (a % p * b % p) % p 
  •  (a^b) % p = ((a % p)^b) % p 

二、快速冪求逆元

乘法逆元的定義

 若整數b,m互質,並且b|a,則存在一個整數x,使得a/bax(mod m),則稱x為b的模m乘法逆元,記為b1(mod m)

b存在乘法逆元的充要條件是b與模數m互質。當模數m為質數時,bm2即為b的乘法逆元。

  因為在模運算中,並沒有除法的性質,即沒有(a/b)%p≠((a%p)/(b%p))%p,而乘法逆元便可以幫助我們將其轉化成乘法形式:a/b % m=ax % m。

  由乘法逆元的定義我們可以推出如下結論:

∵ a/b mod p = a * b-1 mod p = a/b * b * b-1 mod p

∴ b * b-1 ≡ 1(mod p)

費馬小定理

若p是一個質數,且整數a不是p的倍數(a與p互質),則有a p-1 ≡ 1(mod p)。

  基於這個定理,我們就可以推出如下結論:

 ∵ a p-1 ≡ 1(mod p)

∴ a * a p-2 ≡ 1(mod p)

  因此,結合乘法逆元的定義所得到的推論以及費馬小定理,我們可以得到:a-1 = a p-2(mod p)。

  也就是說,當模數p為質數,且整數b不是p的倍數時(b與p互質),b的逆元即為b p-2

代碼實現

  模板題鏈接:快速冪求逆元  

  根據上述結論,要判斷b關於模數p的乘法逆元是否存在,若存在則求出之,我們便只需要計算b p-2即可。而這個計算利用快速冪便可以很快解決。

  代碼如下:

#include <iostream>
#include <algorithm>
#include <cstdio>
using namespace std;
typedef long long ll;

int qmi(int a,int k,int p)
{
    int res=1%p;
    while(k)
    {
        if(k&1)res=(ll)res*a%p;
        a=(ll)a*a%p;
        k>>=1;
    }
    return res;

}

int main()
{
    int n;scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        int a,b;
        scanf("%d%d",&a,&b);
        if(a%b==0)printf("impossible\n");
        else printf("%d\n",qmi(a,b-2,b));
    }
    return 0;
}

應用

  有了乘法逆元,我們在計數類問題中遇到(a/b)%p時,便可以轉化成((a % p) * (b-1 % p)) % p來計算了,這樣便防止了爆int的情況出現,當然,轉化的前提是必須保證b與p互質。當p是質數時,則可以進一步轉化為((a % p) * (b p-2 % p)) % p。


免責聲明!

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



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