一、O(n)求逆元
inv[i]=(MOD−MODi)∗inv[MOD%i]%MOD
证明:
设
t=MODi,k=MOD
则有
t∗i+k≡0(modMOD)
有
−t∗i≡k(modMOD)
两边同时除以
i∗k
得到
−t∗inv[k]≡inv[i](modMOD)
即
inv[i]≡−MODi∗inv[MOD%i](modMOD)
即
inv[i]≡(MOD−MODi∗inv[MOD%i](modMOD)
证毕
适用于MOD是质数的情况,能够O(n)时间求出1~n对模MOD的逆
代码实现:
inv[1]=1;
for (int i=2;i<=n;++i)
inv[i]=(ll)(mod-mod/i)*inv[mod%i]%mod;
二、费马小定理
在模为素数p的情况下,有费马小定理
ap−1≡1(modp)
∴
ap−2≡a−1(modp)
也就是说a的逆元为
ap−2
而在模不为素数p的情况下,有欧拉定理
aϕm≡1(modm)
∴
a−1≡aϕm−1(modm)
因此逆元x便可以套用快速幂求得了
x=aϕm−1
但是似乎还有个问题?如何判断a是否有逆元呢?
检验逆元的性质,看求出的幂值x与a相乘是否为1即可
PS:这种算法复杂度为
O(log2N)
在几次测试中,常数似乎较上种方法大所以当p比较大的时候需要用快速幂求解。
代码实现:
typedef long long ll;
ll pow_mod(ll x, ll n)
{
ll res=1;
while(n>0)
{
if(n&1)res=res*x%mod;
x=x*x%mod;
n>>=1;
}
return res;
}
pow_mod(x,mod-2);