ACM-乘法逆元

乘法逆元

写在前面:本文借鉴了 正义小学生 的博客

(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)
不妨设 a12,且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.线性递推(可以批量求逆元):

线性递推与以上三种求逆元的区别在于:线性递推,递推两字很显然这个方法可以由一个逆元推向其他的逆元,也就是这种方法可以很好的推得多个逆元,而不仅仅是推出一个逆元而已。
ACM-乘法逆元_第1张图片

最后得出的公式可以用来递推逆元:

代码如下:

#include
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;
}

你可能感兴趣的:(算法)