逆元学习笔记

明天就要出去听课,第一天就讲数论搞得我很方,于是趁现在赶紧把我的数论坑补补

逆元

逆元定义

\(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;
}
posted @ 2018-09-29 10:18  _Lancy  阅读(304)  评论(0)    收藏  举报