乘法逆元
写在前面:本文借鉴了 正义小学生 的博客
(1)何为乘法逆元?
在(mod p)的意义下,如果a*a’ = 1,那么我们就说a’是a的逆元。同时容易理解:a也为a’的逆元。
有乘法逆元的前提是 :a,p互质,若a,p不互质,也就意味着不存在a的乘法逆元。
(2)乘法逆元的性质:
本文只选出最重要的几个性质进行说明:
1.存在唯一性:
对于a来说,如果他有逆元,则它只能有一个逆元。
证明:
我们先假设 aa 有两个不相等逆元: a1,a2 ,那么一定有:
a* a1=a* a2=1(mod p)
不妨设 a1<a2,且a2 - a1=k
a*(a2-k)=a*a2(mod p)
a*k=0(mod p)
由于a≠0,所以k=0(mod p)
所以 a2=a1,与题设矛盾。
2.完全积性函数
为了接下来方便,我们把 a 的逆元表示为 inv[a]。
inv[a]* inv[b]=inv[a*b]
证明:
a* inv[a]=b* inv[b]=1(mod p)
a*inv[a] * b *inv[b]=1(mod p)
这就是a*b逆元的定义!
3.a*inv[b]=a/b (mod p)
证明:
b*inv[b]=1(mod p)
两边乘以a得 :a* b* inv[b]=a(mod p)
a* inv[b]=a/ b(mod p)
这个结论很重要:有时候我们需要算出 a/b mod p 的值,用朴素的方法,我们只能在 a 上不断加 p ,直到它能被 b 整除为止。当 a,b,p都很大的时候,这种方法就只能凉凉了,但如果有了逆元,我们就可以非常方便,快捷地求解。
(3)逆元怎么求
1.枚举法
枚举k,检查a*k=1(mod p) 几乎用不到
2.费马小定理(mod p中的p为素数可用)
费马小定理:当 p 为素数时,ap-1=1(mod p)
那么 a*ap-2=1(mod p)
所以a的逆元为 ap-2
3.扩展欧几里得:
a*x=1(mod p)
ax+py=1 这东西不就是exgcd吗
如果不懂exgcd,我之前写了exgcd的详解。点击链接查看
4.线性递推(可以批量求逆元):
线性递推与以上三种求逆元的区别在于:线性递推,递推两字很显然这个方法可以由一个逆元推向其他的逆元,也就是这种方法可以很好的推得多个逆元,而不仅仅是推出一个逆元而已。
最后得出的公式可以用来递推逆元:
代码如下:
#include<bits/stdc++.h>
using namespace std;
int N,p;
int inv[25000528];
int main()
{
cin>>N>>p;
inv[1]=1;
for (int i=2;i<=N;i++)
{
inv[i]=(long long)(p-p/i)*inv[p%i]%p;
}
for (int i=1;i<=N;i++)
printf("%d\n",inv[i]);
return 0;
}
相关文章: