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逆元