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

1、快速冪ios

原理:spa

  快速冪的原理十分簡單。code

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

  這顯然是正確的。由於任何一個數均可以表示成二進制。get

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

代碼實現io

  模板題連接:快速冪模板

  代碼模板以下:時間複雜度O(logk)class

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; }

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

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

  •  (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 

2、快速冪求逆元

乘法逆元的定義

 若整數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。

相關文章
相關標籤/搜索