洛谷 P3811 【模板】乘法逆元
传送门
逆元
什么是逆元?
首先取模运算在加法、减法、乘法中是满足分配率的,即
\((a+b)\%p=(a\%p+b\%p)\%p\)
\((a*b)\%p=((a\%p)*(b\%p))\%p\)
但是除法却不满足。
而有时候\(\frac{b}{a}\%p\)中分子和分母都特别大,需要在计算过程中取模,这时候就需要把其转化成
\(b*x\%p\),其中x叫做a在模p意义下的逆元。即
\(a*x\equiv 1\pmod p\)
怎么求逆元?
-
费马小定理
当a、p互质时,
\(a^{p-1}\equiv1\pmod p\)
即 \(a*a^{p-2}\equiv1\pmod p\)
可以看出,此时\(a^{p-2}\)即为a的逆元。
可以快速幂求出。 -
exgcd
直接根据同余方程\(a*x\equiv 1\pmod p\)用exgcd求解即可。 -
线性递推
用于求 1~n 在%p意义下的逆元。
设p=k*i+r,则\(k*i+r\equiv0\pmod p\)
然后把等式两边同时乘i和r的逆元(\(x^{-1}\)表示x的逆元):
\(k*i*i^{-1}*r^{-1}+r*i^{-1}*r^{-1}\equiv0\pmod p\)
化简得:
\(k*r^{-1}+i^{-1}\equiv0\pmod p\)
再移项可得:
\(i^{-1}\equiv -k*r^{-1}\pmod p\)
把k替换成p/i,r替换成p%i,可以得出递推公式:
\(inv[i]=-(p/i)*inv[p\%i]\%p\)
注意逆元为正数,所以\(inv[i]=(inv[i]+p)\%p\)
AC代码
#include<cstdio>
#include<iostream>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<ctime>
using namespace std;
int n,p,inv[3000005];
int main(){
cin>>n>>p;
inv[1]=1;
printf("1\n");
for(int i=2;i<=n;i++) {
inv[i]=((-(1ll)*(p/i)*inv[p%i])%p+p)%p;
printf("%d\n",inv[i]);
}
return 0;
}

浙公网安备 33010602011771号