明天就要出去听课,第一天就讲数论搞得我很方,于是趁现在赶紧把我的数论坑补补
逆元
逆元定义
若 (a imes xequiv 1 pmod b),(a),(b)互质,则称(x)为(a)的逆元,记为(a^{-1})
逆元求法
扩展欧几里得
利用扩展欧几里得求线性同余方程(a imes xequiv cpmod b)
我们知道扩展欧几里得可以求出线性方程组的系数,所以我们就可以求出当(c=1)的情况的线性方程组,则可以转换为
[a imes x+b imes 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
",x);
}
费马小定理
下面是费马小定理的定义
若(p)为素数,(a)为正整数,且(a、p)互质,则就有下列通项公式
[a^{p-1}equiv 1 pmod p ]
所以根据逆元的定义与费马小定理的定义
[egin{aligned}
a imes x&equiv 1 & pmod b \
a imes 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
",ksm(i,p-2));
}
线性求逆元
这个其实理解起来也比较简单。
线性求逆元,我们就要用递推的形式,设(A[i])为第(i)个数的逆元。
首先我们知道(1)的逆元是(1)
然后我们设(p=k imes i+r),然后将此式子放到(mod p)意义下:
(k imes i+requiv 0pmod p)
然后两边同时乘上(i^{-1},r^{-1})就会得到
[egin{aligned}
k imes r^{-1}+i^{-1}&equiv0 & pmod p\
i^{-1}&equiv -k imes r^{-1} & pmod p\
i^{-1}&equiv -left[frac{p}{i}
ight] imes p mod 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;
}