数论篇4——逆元(数论倒数)

问题引入

对于取余运算,有一下一些性质:

 数论篇4——逆元(数论倒数)_第1张图片

但是唯独除法是不满足的:

 

 为什么除法错的呢?很好证明:

 数论篇4——逆元(数论倒数)_第2张图片

 而对于一些题目,我们必须在中间过程中进行求余,否则数字太大,电脑存不下,那如果这个算式中出现除法,我们就需要逆元了。

逆元

定义:

 数论篇4——逆元(数论倒数)_第3张图片

对于c,在数值上就不一定等于我们常规意义上的倒数了,我们可以理解为要求在0,1,2……p-1之间找一个数,是的这个数和a相乘后再取模p,得到的结果为1。

现在就要在回到刚才的问题了,除以一个数等于乘上这个数的倒数,在除法取余的情况下,就是乘上这个数的逆元,即:

 

这样就把除法,完全转换为乘法了。

逆元的求解

对于逆元的求解,如果n较小的话,是容易算出来的,例如,求3在模26下的逆元:

数论篇4——逆元(数论倒数)_第4张图片

但是当n非常大的时候,手动求解就非常困难了。

(1)扩展欧几里得算法(extend_gcd)

数论篇4——逆元(数论倒数)_第5张图片

模数可以不为质数,满足gcd(a,b)=1即可

定义:

对于逆元的表达式可以做一些变换:

 数论篇4——逆元(数论倒数)_第6张图片

 当gcd(a,b)=1时,代入extend_gcd(a,b,x,y),得到的非负的x值,就是上面的a-1

int extend_gcd(int a, int b, int& x, int& y) {
    if (b == 0) {
        x = 1, y = 0;
        return a;
    }
    int q = extend_gcd(b, a % b, x, y);
    int temp = x;
    x = y;
    y = temp - a / b * y;
    return q;
}

(2)费马小定理

只适用于模数为质数的情况 

如果p是一个质数,且a不是p的倍数则有

 数论篇4——逆元(数论倒数)_第7张图片

两边同除以 a

数论篇4——逆元(数论倒数)_第8张图片

所以

 数论篇4——逆元(数论倒数)_第9张图片

用快速幂求一下,复杂度O(logn)

(3)线性递推逆元(神奇小饼干法)

只适用于模数为质数的情况

当p为质数时有

证明:

 数论篇4——逆元(数论倒数)_第10张图片

写成算法就是一个递归,到1为止,因为1的逆元就是1

int inv(int t, int p) {
    return t == 1 ? 1 : (p - p / t) * inv(p % t, p) % p;
}

这个方法复杂度是O(n),但并不是说比前两个差,它可以在O(n)的复杂度内算出n个数的逆元,上面的算法加一个记忆性搜索就行了

int inv(int t, int p) {
    return INV[t] = t == 1 ? 1 : (p - p / t) * inv(p % t, p) % p;
}

 

你可能感兴趣的:(数论篇4——逆元(数论倒数))