逆元杂烩
逆元,简单来说就是为了满足在取模式下的除法需要(+-*可在取模式下正常进行,除法不行) 同余式规则见同余入门
用数学式说 ax≡1(mod p) 则x为a在膜p意义下的逆元
求法:
1.欧拉定理法
根据欧拉定理a^£(p)≡1(mod p)
x=a^£(p)-1
所以就可以求欧拉函数+快速幂求逆元
条件gcd(a,p)=1
时间:o(sqrt(n))
2.费马小定理
根据费马小定理a^(p-1)≡1(mod p)
x=a^(p-2)
所以快速幂直接解决
条件:p为质数
时间:o(log(p))
3.exgcd
ax≡1(mod p)
ax-py=1
用exgcd求其最小解即可
条件a,p互质
时间:o(log(a))
代码:
il void exgcd(int a,int b,ll &x,ll &y)
{
if(!b) x=1,y=0;
else exgcd(b,a%b,y,x),y-=a/b*x;
}
4.线性递推求逆元
设p=ki+t≡0(mod p)
k+t*i^(-1)≡0(mod p)
t * i^(-1)≡-k(mod p)
i^(-1)≡-k*t^(-1) (mod p)
i^(-1)≡p-k*t^(-1) (mod p)
inv[i]≡p-(p/i)*inv[p%i] (mod p)
限制:无
时间:o(n) (一下求n个,且是线下算法)
代码:
for(int i=2;i<=n;i++) inv[i]=p-(p/i)*inv[p%i]%p;
5.阶乘法求逆元
对于一串数a1,a2,……,an 求每个数的逆元
首先维护数一个累积数组s,s[i]=a1a2……ai
然后,再求s[n]的逆元,记为inv[n+1](inv数组表示1/(a1a2……ai-1))
最后,反向for一遍,ai的逆元为s(i-1)inv(i+1)(a1 a2……ai-1/(a1 a2……*ai)==1/ai)
限制:无
时间:o(n) (一下求n个,且是线下算法)
代码:
s[0]=1;
for(ri i=1;i<=n;i++)
{
a[i]=read();
s[i]=(s[i-1]*a[i])%p;
}
inv[n+1]=ksm(s[n],p-2);
for(ri i=n;i>=1;i--)
{
inv[i]=(inv[i+1]*a[i])%p;
}
for(ri i=1;i<=n;i++)
{
ny[i]=(inv[i+1]*s[i-1])%p;
}
以上是常规求逆元方法,还有其他方法望各位挖掘