逆元(数论中的倒数)

满足求余的运算

(a +  b) % p = (a%p +  b%p) %p  (对)

(a  -  b) % p = (a%p  -  b%p) %p  (对)

(a  *  b) % p = (a%p *  b%p) %p  (对)

(a  /  b) % p = (a%p  /  b%p) %p  (错)

除法不满足求余取模运算

 

a*x  = 1 (mod p)       其中x叫做a关于p的逆元

比如2 * 3 % 5 = 1,(即2*3=1(mod 5))那么3就是2关于5的逆元,或者说2和3关于5互为逆元

 

a的逆元,我们用inv(a)来表示

那么(a  /  b) % p = (a * inv(b) ) % p = (a % p * inv(b) % p) % p

 

逆元:

a和p互质,a才有关于p的逆元

 

typedef long long ll;
ll ex_gcd(ll a,ll b,ll &x,ll &y)
{
    if(b==0)
    {
        x=1,y=0;
        return a;
    }
    ll ans=ex_gcd(b,a%b,y,x);
    y-=a/b*x;
    return ans;
}
ll Cal(ll a,ll b,ll c)//求最小的x使ax+by=c
{
    ll x,y;
    ll gcd=ex_gcd(a,b,x,y);
    if(c%gcd) return -1;//无解
    x*=c/gcd;
    b/=gcd;
    if(b<0) b=-b;
    ll ans=x%b;
    if(ans<=0) ans+=b;
    return ans;
}
int Cal(int a,int b)//求最小的x使ax+by=1
{
    int x,y;
    int gcd=ex_gcd(a,b,x,y);
    if(1%gcd) return -1;//无解
    x*=1/gcd;
    b=abs(b);
    int ans=x%b;
    if(ans<=0) ans+=b;
    return ans;
}

 

求逆元方法1:

由费马小定理 a^(p-1) ≡1 (mod p)

两边同除以a得:a^(p-2) ≡ inv(a) (mod p)

所以inv(a) = a^(p-2) (mod p)

这个用快速幂可以求,复杂度O(logn)

LL quickPow(LL a,LL b,LL mod)           //(a^b)%mod
{
    LL res=1;
    while(b>0){
        if(b&1)
            res=(res%mod*a%mod)%mod;
        b>>=1;
        a=(a%mod*a%mod)%mod;
    }
    return res;
}
LL Fermat(LL a, LL p)               //费马求a关于b的逆元 
{
        return quickPow(a,p-2,p);
}

 

 

求逆元方法2: 

扩展欧几里德算法

a*x + b*y = 1如果ab互质,有解。 这个解的x就是a关于b的逆元,y就是b关于a的逆元

 

证明:两边同时求余b

a*x % b + b*y % b = 1 % b

a*x % b = 1 % b

a*x = 1 (mod b)

所以x是a关于b的逆元,反之可证明y是b关于a的逆元

#include
typedef long long LL;
void ex_gcd(LL a, LL b, LL &x, LL &y, LL &d){
    if(!b) 
    {
        d=a;
        x=1‘
        y=0;
    }
    else
    {
        ex_gcd(b,a%b,y,x,d);
        y-=x*(a/b);
    }
}
LL inv(LL t, LL p)     //如果不存在,返回-1 
{
    LL d, x, y;
    ex_gcd(t,p,x,y,d);
    return d==1?(x%p+p)%p:-1;
}
int main()
{
    LL a,p;
    while(~scanf("%lld%lld",&a,&p)
    {
        printf("%lld\n",inv(a, p));
    }
}

 

 

求逆元方法3:

当p是质数的时候有inv(a) = (p - p / a) * inv(p % a) % p

#include
typedef long long LL;
LL inv(LL t, LL p)  //求t关于p的逆元,注意:t要小于p,最好传参前先把t%p一下 
{
    return t==1?1:(p-p/t)*inv(p%t,p)%p;
}
int main()
{
    LL a,p;
    while(~scanf("%lld%lld",&a,&p))
    {
        printf("%lld\n",inv(a%p,p));
    }
}

 

 

在O(n)的时间复杂度内算出n个数的逆元

#include
const int N=200000+5;
const int MOD=(int)1e9+7;
int inv[N];
int init()
{
    inv[1]=1;
    for(int i=2;i

 

 

你可能感兴趣的:(数论--逆元)