逆元

  1、何为逆元

  有的时候,我们要在模p的意义下,求一个事件的概率期望,这就要用逆元,因为分数很容易除不尽,而a/b在模p意义下即为a*(b在模p意义下的逆元),这样就能避免无限循环的情况。

  一个数的逆元定义为:数为a,模数为p,逆元为b,那么,满足a*bmod p=1.

  2.1、费马小定理求逆元

  费马小定理能够求数与模数互质情况的逆元,根据费马小定理,若a、p互质,b为a的逆元,那么ap-1 mod p=1,也就是说,ap-1 mod p=a*b mod p,即b=ap-2 mod p,所以逆元为原数的p-2次幂模p。

  如何求呢?我们考虑到了快速幂,即可logp求出逆元。

  以下为代码:

#include<bits/stdc++.h>
using namespace std;
long long n,p,y,he,ans;
int main()
{
    scanf("%lld%lld",&n,&p);//读入n、p
    y=p-2;//乘p-2次
    he=1;
    ans=n;
    while(y)
    {
        if (y&1) he=(he*ans)%p;
        ans=(ans*ans)%p;
        y/=2;//快速幂
    }
    printf("%lld",ans*he%p);//输出
    return 0;
}

  2.2、扩展欧几里得算法求逆元

  我们用扩展欧几里得算法可以求ax+by=1的值一组解,再通过将a作为所求数,b为模数,明显的,求出的x即为a模p的逆元。

  代码如下:

#include<bits/stdc++.h>
using namespace std;
int a,p,x,y;
void gcd(int a,int b,int &x,int &y)//扩展欧几里得算法
{
    if (b==0)
    {
        x=1;
        y=0;
        return;
    }
    gcd(b,a%b,x,y);
    int t=x;
    x=y;
    y=t-(a/b)*y;
}
int main()
{
    scanf("%d%d",&a,&p);
    gcd(a,p,x,y);
    printf("%d",(x+p)%p);//注意x可能为负数
    return 0;
}

  3、线性求1~n逆元

  

posted @ 2019-08-12 10:24  冰逝  阅读(213)  评论(0编辑  收藏  举报