乘法逆元,通常是用來求html
的值,p一般爲質數c++
若a*x≡1(mod b),且a與b互質,咱們定義x是a的逆元,記爲a^(-1),因此也能夠說x是a在mod b意義下的倒數算法
因此對於a/b(mod p),咱們能夠先求出b在mod p下的逆元,而後乘a再mod p就是這個分數的值了spa
首先看到同餘方程,這個就是典型的求一個數模p下的逆元,而對於逆元的求法,咱們有多種操做:3d
首先,這個算法的性質以下rest
擴展歐幾里德算法是用來在已知a, b求解一組x,y,使它們知足貝祖等式: ax+by = gcd(a, b) =d(解必定存在,根據數論中的相關定理)。擴展歐幾里德經常使用在求解模線性方程及方程組中。
在這道題中,咱們能夠把ax≡1(mod b)轉化成ax+by=1,只不過y多是負數,然而與擴歐公式仍是有差異,但不可貴出,gcd(a,b)=1,code
推導公式以下htm
由最大公因數的定義,可知 a 是 gcd(a,b) 的倍數,且 b 是 gcd(a,b) 的倍數, 若 x,y 都是整數,就肯定了 ax + by 是 gcd(a,b) 的倍數, 由於 m = ax + by因此 m 必須是 gcd(a,b) 的倍數, 那麼 m \mod gcd(a,b) = 0
..................................................blog
而後根據一系列推導就得出了具體公式:具體請見同餘方程第一篇題解<<<<大佬。ci
1 #include<bits/stdc++.h> 2 using namespace std; 3 long long x,y; 4 void exgcd(long long a,long long b) 5 { 6 if(b==0) 7 { 8 x=1; 9 y=0; 10 return; 11 } 12 exgcd(b,a%b); 13 long long z=x; 14 x=y; 15 y=z-(a/b)*y; 16 } 17 int main() 18 { 19 long long a,b; 20 cin>>a>>b; 21 exgcd(a,b); 22 while(x<0) 23 x+=b; 24 x%=b; 25 cout<<x; 26 return 0; 27 }
這個作法運用到了費馬小定理
若p爲素數,a爲正整數,且a、p互質。 則有a^(p-1)≡1(mod p)。
而後代入原式,神奇的事發生了
a*x≡1(mod p) a*x=a^(p-1) (mod p) x=a^(p-2) (mod p)
而後咱們求a^(p-2)(mod p)就是它的逆元啦
1 #include<bits/stdc++.h> 2 #define ll long long 3 using namespace std; 4 ll n,p; 5 int fpm(ll x,ll y)//快速冪 6 { 7 x%=p; 8 ll ans=1; 9 while(y) 10 { 11 if(y&1)ans=(ans*x)%p; 12 y>>=1; 13 x=x*x%p; 14 } 15 return ans; 16 } 17 int main() 18 { 19 cin>>n>>p; 20 for(int i=1;i<=n;i++) 21 { 22 printf("%lld\n",fpm(i,p-2)); 23 } 24 }
以上算法針對於求單個逆元,可是有一長串的時候,你就TLE了,因此,聰明的大佬們研發的線性算法出現了。
設x的逆元爲x^(-1)
咱們先有一個1的逆元爲1
設p=k*i+r,(1<r<i<p) 也就是 k 是 p / i的商,r是餘數 。
而後乘上i的逆元和r的逆元
而後公式就出來了
1 #include<bits/stdc++.h> 2 #define ll long long 3 using namespace std; 4 ll n,p; 5 ll inv[3000005]; 6 int main() 7 { 8 cin>>n>>p; 9 inv[1]=1; 10 printf("%lld\n",inv[1]); 11 for(int i=2;i<=n;i++) 12 { 13 inv[i]=(p-p/i)*inv[p%i]%p; 14 printf("%lld\n",inv[i]); 15 } 16 }
學會了求逆元后,咱們就能夠學學其餘interesting的東西——中國剩餘定理