逆元方法总结

                                          逆元(inv)

1.逆元

若a*x≡1(mod b) ,a,b互质,则称x为a的逆元。

A/B %p=A*inv(B)  %p inv(B)为B的逆元

2.应用

(a/b)%m 时,因b可能会过大,会出现爆精度的情况,且除法不满足同余拆分定理。

3.求逆元的方法

(1).费马小定理

  

m是素数的情况下,对任意整数都有。 
如果无法被整除,则有。 
可以在为素数的情况下求出一个数的逆元,,即为逆元。

假设数据范围1<=x<=10^9,p=1000000007,p是素数;

所以x肯定就无法被p整除啊,所以最后就得出x^(p-2)为x的逆元啦。

复杂度O(logn);

代码:

const int mod = 1000000009;
long long quickpow(long long a, long long b) {
    if (b < 0) return 0;
    long long ret = 1;
    a %= mod;
    while(b) {
        if (b & 1) ret = (ret * a) % mod;
        b >>= 1;
        a = (a * a) % mod;
    }
    return ret;
}
long long inv(long long a) {
    return quickpow(a, mod - 2);
}

 (2)扩展欧几里得算法求逆元

例如:4关于17的乘法逆元为多少?

4X≡1 mod 7

这个方程等价于求一个XK,满足

4X=7K+1

其中XK都是整数。

求x,k就是扩展欧几里得算法

可扩展欧几里得求逆元ax≡1(mod n)其中a,n互质

根据逆元的定义,则可以转化为a*x+b*y=1。这样就可以用扩展欧几里得算法求x了。

注意:在gcd不为1说明逆元不存在(因为c=1,c%gcd==0为有整数解的充分必要条件),若为1,调整x0到0~m-1的范围中即可

适用条件:

复杂度:O(logn);

代码:

//返回d = gcd(a, b);和对应于等式ax + by = d中的x、y
int ex_gcd(int a,int b,int &x,int &y)       //扩展欧几里得 
{
    if(b==0)
    {
        x=1;
        y=0;
        return a;
    }
    int r=ex_gcd(b,a%b,x,y);
    int t=x;
    x=y;
    y=t-a/b*y;
    return r;
}
int mod_reverse(int a,int b)//a*x=1(mod b) 求a的逆元x 
{
    int d,x,y;
    d=ex_gcd(a,b,x,y);
    if(d==1)
        return (x%b+b)%b;
    else
        return -1;
}



 

简洁写法I

* 只能求a < m的情况,且a与m互质

* 求ax = 1(mod m)的x值,即逆元(0 < a < m)

long long inv(long long a,long long m){
 if(a == 1)return 1;
 return inv(m%a,m)*(m-m/a)%m;
}
//x[i]=temp/a[i][i]%mod
x[i] = (temp*inv(a[i][i],mod))%mod;

(3) 逆元线性筛 ( P为质数 )

 

求1,2,...,N关于P的逆元(P为质数)

复杂度:O(N)

代码:

const int mod = 1000000009;
const int maxn = 10005;
int inv[maxn];
inv[1] = 1;
for(int i = 2; i < 10000; i++)
    inv[i] = inv[mod % i] * (mod - mod / i) % mod;


 

如果是求阶乘的逆元呢?(阶乘数组:fac[ ])

代码:

inv[maxn]=mod_pow(fac[maxn],mod-2);
for(ll i=maxn-1;i>=0;i--)
    inv[i]=(inv[i+1]*(i+1))%mod;

(4)

但是你会发现费马小定理和扩展欧几里得算法求逆元是有局限性的,它们都会要求互素。实际上我们还有一

种通用的求逆元方法,适合所有情况。公式如下

 

          

 

现在我们来证明它,已知,证明步骤如下

 

          

 

方法八 、递推O(1)就能求出每一个的逆元

#define MOD 1000000007
#define N 500005
LL inv[N],c[N],a[N];
//预处理逆元 i (i

 

 

你可能感兴趣的:(模板,2018暑假ACM集训,数学----数论)