逆元总结

乘法逆元,有 一个作用就是,除以一个数再取模时,可以将这个数乘以这个数的逆元再取模,就是将除法运算转化为乘法运算,举个例子:

 先说一下什么是逆元:若对于数字A,C 存在X,使A * X ≡ 1 (mod C) ,那么称X为 A 对C的乘法逆元。

比如:( 4 , 7 ) 的逆元是2,4*2≡ 1(mod 7)

          12 / 4mod 7=(12 / 4)* (4 * 2) mod 7 

这样看除法就被转化为乘法了;

关于逆元有三种求法:

1、费马小定理 (O(nlogn)的复杂度,但若n达到1e7会爆炸,所以需要线性求逆元的方法)

根据费马小定理,我们可得出当p是素数时,对任意x,都有x^(p)≡  x(modp),

若x无法被p整除,那么x^(p-1)≡  1(modp),

那么可得出当模数p为素数x^(p-2)就是x的逆元。

代码如下:

const ll mod=1e9+7;
ll pow_mod(ll a,ll b)
{
    ll res=1;
    while(b>0)
    {
        if(b&1)res=res*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return res;
}
ll inv(ll a)
{
    return pow_mod(a,mod-2);
}

2、扩展欧几里德算法

a*x + b*y = 1

如果ab互质,有解。

那么两边同时modp

ax%p≡1%p那么ax≡1(modp)

x就是a关于b的逆元

ll x,y,mod;
ll extgcd(ll a,ll b,ll& x,ll& y)
{
    ll d=a;
    if(b!=0)
    {
        d=extgcd(b,a%b,y,x);
        y-=(a/b)*x;
    }
    else x=1,y=0;
    return d;
}
ll inv(ll a)
{
    ll d=extgcd(a,mod,x,y);
    return d==1?(x%mod+mod)%mod:-1;
}
int main()
{
    while(cin>>x>>mod)
    {
        cout<<inv(x)<<endl;
    }
    return 0;
}

3、逆元线性筛法

 用来求1,2,3....n关于p的逆元,复杂度O(n)

#define MAX 2005
const ll mod=1e9+7;
int inv[MAX];
int main()
{
    ll x;
    inv[1]=1;
    for(int i=2;i<MAX;i++)
        inv[i]=inv[mod%i]*(mod-mod/i)%mod;
    while(cin>>x)
    {
        cout<<inv[x]<<endl;
    }
    return 0;
}

以上的代码均是本人测试过,如有错误,欢迎指正!

参考博客:https://blog.csdn.net/qq_37632935/article/details/77806853

                 https://blog.csdn.net/nucshiyilang/article/details/62044362

猜你喜欢

转载自www.cnblogs.com/zhgyki/p/9446206.html