学习逆元

转载地址1:http://www.cnblogs.com/mjtcn/p/7241896.html

转载地址2:https://blog.youkuaiyun.com/acdreamers/article/details/8220787

 

对于正整数,如果有,那么把这个同余方程中的最小正整数解叫做的逆元。

逆元一般用扩展欧几里得算法来求得,如果为素数,那么还可以根据费马小定理得到逆元为

推导过程如下

                            

 

求现在来看一个逆元最常见问题,求如下表达式的值(已知

 

           

 

当然这个经典的问题有很多方法,最常见的就是扩展欧几里得,如果是素数,还可以用费马小定理。

 

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

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

 

          

 

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

 

          

 

 

定义

乘法逆元的定义:若存在正整数a,b,p, 满足ab = 1(mod p), 则称a 是b 的乘法逆元, 或称b 是a 的乘法逆元。b ≡ a-1 (mod p),a ≡ b-1 (mod p)

比如说, 在模7 意义下,3 的乘法逆元是5, 也可以说模7 意义下5的乘法逆元是3。模13意义下5的逆元是8……

 

存在性

看起来和同余方程很相似(其实下面真的可以用exgcd求的!),在同余方程中

ab ≡ 1(mod p)

若a 与p 互质, 则一定存在一个正整数解b, 满足b < p,若a 与p 不互质, 则一定不存在正整数解b.

所以逆元要求a与p互质

 

求法

求逆元有三种求法,

1、扩展欧几里得

可以用扩展欧几里得求,那么是怎么个求法呢?

扩展欧几里得是用来求这样的一组解的:ax+by = gcd(a,b),求x和y,(求出x后自然知道了y,所以算是求一个x)。

逆元呢是求这样的一个解:ax ≡ 1 (mod b),(为了方便理解,改了一下变量名),求x,貌似并没有一点点相似处,那么我们变一下,

ax+by = gcd(a,b),变成 ax+by = c;

ax ≡ 1 (mod b),变成 ax-by = 1;如果将y看成负的,ax+by = 1;

完全一样嘛,所以直接套用扩展欧几里得求就好了。

代码

#include<cstdio>

int exgcd(int a,int b,int &x,int &y)
{
    if (b==0)
    {
        x = 1;
        y = 0;
        return a;
    }
    int r = exgcd(b,a%b,x,y);
    int tmp = x;
    x = y;
    y = tmp-a/b*y;
    return r;
}

int main()
{
    //gcd(a,p)==1
    int a,p,r,x,y;
    while (scanf("%d%d",&a,&p)!=EOF)
    {
        r = exgcd(a,p,x,y);
        printf("%d",(x%p+p)%p);
    }
    return 0;
}

扩展欧几里得求逆元

 

2、线性求逆元

先纠正一下变量名,再改回来ab ≡ 1(mod p),求b

p%a = p-(p/a)*a;  在c++中/为整除。

(p/a)*a = p-(p%a);  换下位置

(p/a)*a = -(p%a);  在模p意义下p可以约掉,可以没有这一步

a = -(p%a)/(p/a);  再换一下位置

a-1 = -(p%a)-1*(p/a);

所以a-1可以用(p%a)-1推出,所以就可以用递推式来推出1到a的所有数的逆元。

代码

int inv[MAXN]; 
void INV(int a,int p)//线性求到a的逆元 
{
    inv[1] = 1;
    for (int i=2; i<=a; ++i)
        inv[i] = (-(p/i))*inv[p%i]%p; 
}

线性求逆元1

下面的代码只求一个值的逆元,运用的是上面的式子

int INV(int a)//线性求a的逆元 
{
     if (a==1) return 1;
     return ((-(p/a)*INV(p%a))%p);
}

 

3、欧拉定理求逆元

欧拉定理:aφ(p) ≡ 1(mod p)

对于任意互质的a,p 恒成立。

欧拉定理用来求逆元用的是欧拉定理的一个推论:
a*aφ(p)-1 ≡ 1(mod p

仔细观察,a*b ≡ 1(mod p),在这里的b不就是上面的aφ(p)-1吗?,所以求出aφ(p)-1就好了。

所以我们用快速幂就可以求出乘法逆元了。

这个方法它需要多算一个欧拉函数,代码这里不再给出。

补充:其实如果p是质数的话,可以用费马小定理,与欧拉定理是完全一样的,费马小定理在p不是质数时,则只能用欧拉定理。

怎么弄呢?费马小定理 a(p-1) ≡ 1(mod p) p是质数,且a,p互质,

然后将上面的式子变一下,a*a(p-2) ≡ 1(mod p) ,

再变一下,a(p-2) ≡ a-1 (mod p) ,然后求出a(p-2)就可以了。

然后再看一下欧拉定理,如果p是质数,φ(p) = p-1,那么我们求aφ(p)-1,也就是求a(p-2)。和费马小定理是一样的。

 

应用

我们知道(a+b)%p = (a%p+b%p)%p

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

求(a/b)%p时,可能会因为a是一个很大的数,不能直接算出来,也无法像上面一样分解。

我们可以通过求b关于p的乘法逆元k,k ≡ b-1 (mod p) ,将a乘上k再模p,即(a*k) mod p。其结果与(a/b) mod p等价。

然后这就成了求a*k%p,然后就可以用那两个公式了。

 

个人理解

对于个人的理解逆元,逆元是在运算除时,可以变成乘,方便计算,像上面一样,a/b(mod p)就可以变成a*b-1,这也就是逆元的本质,必须要在的意义下才有效。

运算a/b时,我们除以b就相当于乘以1/b,这是个分数,不利于计算,所以我们就找到了一个整数,b的逆元,比如计算12/3(mod 7),这是个除法,所以我们可以这样12*(1/3),虽然是乘法了,但是有分数,所以找一个整数使得x,3x≡1(mod 7),x=5,即模7意义下3的逆元是5,然后我们乘以这个逆元,12*5 = 60,60 mod 7 = 4,诶,12/3 = 4,相等啊,这就是上面所说的性质,

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值