1、快速冪ios
原理:spa
快速冪的原理十分簡單。code
ak=a2^0*a2^1*a2^2*…a2^x,其中k=20+21+22+…+2x。blog
這顯然是正確的。由於任何一個數均可以表示成二進制。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/b≡a∗x(mod m),則稱x爲b的模m乘法逆元,記爲b−1(mod m)。
b存在乘法逆元的充要條件是b與模數m互質。當模數m爲質數時,bm−2即爲b的乘法逆元。
由於在模運算中,並無除法的性質,即沒有(a/b)%p≠((a%p)/(b%p))%p,而乘法逆元即可以幫助咱們將其轉化成乘法形式:a/b % m=a∗x % 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。