乘法逆元總結 3種基本方法
阿新 • • 發佈:2019-01-02
逆元
逆元(inverse element)是在取模意義下,不能直接除以一個數,而要乘以它的逆元;a*b
1 (mod p) , 那麼a和b互為模p意義下的逆元,比如要計算(x/a)%p
,可以寫成x*b%p
;
方法一
費馬小定理
若P為素數,則
1 (mod p) 【費馬小定理】
即:
*a
1 (mod p)
所以
就是a在模p意義下的逆元
const LL mod = 1e9+7;
//快速冪
LL fastPow(LL a,LL b){
LL ans=1;
while(b){
if(b&1)
ans=(ans*a)%mod;
a=(a*a)%mod;
b>>=1;
}
return ans;
}
//求x的逆元
LL inv(LL x){
return fastPow(x,mod-2);
}
尤拉定理
若a和p互素(P不一定是素數),則
1 (mod p)
即
1 (mod p)
所以
就是a在模p意義下的逆元
聯絡
稱為尤拉函式,表示小於等於P且與P互素的個數,顯然若p為素數,則
const LL mod = 1e9+7;
//求尤拉函式
long long phi(long long x)
{
long long res = x;
for(long long i=2;i*i<=x;i++)
{
if(x%i==0)
{
res = res/i*(i-1);//res -= res/i;
while(x%i==0)
x/=i;
}
}
if(x>1)res =res/x*(x-1);//res -= res/x;
return res;
}
//快速冪
LL fastPow(LL a,LL b){
LL ans=1;
while(b){
if(b&1)
ans=(ans*a)%mod;
a=(a*a)%mod;
b>>=1;
}
return ans;
}
//求x的逆元
LL inv(LL x){
return fastPow(x,phi(mod)-1);
}
方法二
擴充套件歐幾里得演算法
a*b
1 (mod p)
a * b+k * p = 1
a就是要求的逆元
LL exgcd(LL a,LL b,LL &x,LL &y)//擴充套件歐幾里得演算法
{
if(b==0)
{
x=1,y=0;
return a;
}
LL ret=exgcd(b,a%b,y,x);
y-=a/b*x;
return ret;
}
LL getInv(LL a,LL mod)//求a在mod下的逆元,不存在逆元返回-1
{
LL x,y;
LL d=exgcd(a,mod,x,y);
return d==1?(x%mod+mod)%mod:-1;
}
方法三:遞推求逆元
P是模數,i是待求的逆元,我們求的是
在mod P意義下的值
p=k*i+r,若(r<i),則有k=p/i,r=p%i
k * i+r
1 (mod p)
兩邊同時除以i*r
,
移項得:
即:
* inv[i % mod p]
邊界條件是 inv[1]=1
LL inv[mod+5];
void getInv(LL mod)
{
inv[1]=1;
for(int i=2;i<mod;i++)
inv[i]=(mod-mod/i)*inv[mod%i]%mod;
}