逆元学习笔记
明天就要出去听课,第一天就讲数论搞得我很方,于是趁现在赶紧把我的数论坑补补
逆元
逆元定义
若 \(a\times x\equiv 1 \pmod b\),\(a\),\(b\)互质,则称\(x\)为\(a\)的逆元,记为\(a^{-1}\)
逆元求法
扩展欧几里得
利用扩展欧几里得求线性同余方程\(a\times x\equiv c\pmod b\)
我们知道扩展欧几里得可以求出线性方程组的系数,所以我们就可以求出当\(c=1\)的情况的线性方程组,则可以转换为
\[a\times x+b\times y=1
\]
此时\(x\)就是我们要求的逆元
LL exgcd(LL a,LL b,LL &x,LL &y) {
LL d=0;
if(!b)x=1,y=0,d=a;
else {
d=exgcd(b,a%b,y,x);
y -= (a/b)*x;
}
return d;
}
main(){
exgcd(a,b,x,y);
x=(x%b+b)%b;
printf("%lld\n",x);
}
费马小定理
下面是费马小定理的定义
若\(p\)为素数,\(a\)为正整数,且\(a、p\)互质,则就有下列通项公式
\[a^{p-1}\equiv 1 \pmod p \]
所以根据逆元的定义与费马小定理的定义
\[\begin{aligned}
a\times x&\equiv 1 & \pmod b \\
a\times x&\equiv a^{p-1} & \pmod b \\
x&\equiv a^{p-2} &\pmod b
\end{aligned}
\]
所以我们就可以用快速幂快速求出\(a^{p-2}\pmod b\)的值了,这个就是他的逆元
LL ksm(LL x,LL y) {
LL z=1;
while(y) {
if(y&1) z=(z*x)%p;
x=(x*x)%p;
y>>=1;
}
return z;
}
main(){
printf("lld\n",ksm(i,p-2));
}
线性求逆元
这个其实理解起来也比较简单。
线性求逆元,我们就要用递推的形式,设\(A[i]\)为第\(i\)个数的逆元。
首先我们知道\(1\)的逆元是\(1\)
然后我们设\(p=k\times i+r\),然后将此式子放到\(mod\ p\)意义下:
\(k\times i+r\equiv 0\pmod p\)
然后两边同时乘上\(i^{-1},r^{-1}\)就会得到
\[\begin{aligned}
k\times r^{-1}+i^{-1}&\equiv0 & \pmod p\\
i^{-1}&\equiv -k\times r^{-1} & \pmod p\\
i^{-1}&\equiv -\left[\frac{p}{i}\right]\times p \bmod i^{-1} & \pmod p
\end{aligned}
\]
于是递推式就是下方
A[i] = -(p/i)*A[p % i];
更博更博
逆元的应用
求组合数
我们可以预处理出阶乘,然后如果有模数的话就可以求
for(int i=1;i<=n;i++) fac[i]=fac[i-1]*i,inv[i]=ksm(fac[i],mod-2);
LL c(int n,int m){
return fac[n] * inv[m]%mod * inv[n-m]%mod;
}