逆元(inverse element)是在取模意义下,不能直接除以一个数,而要乘以它的逆元;a*b ≡ \equiv ≡ 1 (mod p) , 那么a和b互为模p意义下的逆元,比如要计算(x/a)%p
,可以写成x*b%p
;
若P为素数,则 a p − 1 {a^{p-1}} ap−1 ≡ \equiv ≡ 1 (mod p) 【费马小定理】
即: a p − 2 {a^{p-2}} ap−2 *a ≡ \equiv ≡ 1 (mod p)
所以 a p − 2 {a^{p-2}} ap−2就是a在模p意义下的逆元
const LL mod = 1e9+7;
//快速幂
LL fastPow(LL a,LL b){
LL ans=1;
while(b){
if(b&1)
ans=(ans*a)%mod;
a=(a*a)%mod;
b>>=1;
}
return ans;
}
//求x的逆元
LL inv(LL x){
return fastPow(x,mod-2);
}
若a和p互素(P不一定是素数),则 a ϕ ( p ) {a^{\phi{(p)}}} aϕ(p) ≡ \equiv ≡ 1 (mod p)
即 a ϕ ( p ) − 1 ∗ a {a^{\phi{(p)}-1}}*a aϕ(p)−1∗a ≡ \equiv ≡ 1 (mod p)
所以 a ϕ ( p ) − 1 {a^{\phi{(p)}-1}} aϕ(p)−1 就是a在模p意义下的逆元
ϕ ( p ) {\phi{(p)}} ϕ(p)称为欧拉函数,表示小于等于P且与P互素的个数,显然若p为素数,则 ϕ ( p ) = p − 1 {\phi{(p)}}=p-1 ϕ(p)=p−1
const LL mod = 1e9+7;
//求欧拉函数
long long phi(long long x)
{
long long res = x;
for(long long i=2;i*i<=x;i++)
{
if(x%i==0)
{
res = res/i*(i-1);//res -= res/i;
while(x%i==0)
x/=i;
}
}
if(x>1)res =res/x*(x-1);//res -= res/x;
return res;
}
//快速幂
LL fastPow(LL a,LL b){
LL ans=1;
while(b){
if(b&1)
ans=(ans*a)%mod;
a=(a*a)%mod;
b>>=1;
}
return ans;
}
//求x的逆元
LL inv(LL x){
return fastPow(x,phi(mod)-1);
}
a*b ≡ \equiv ≡ 1 (mod p)
a * b+k * p = 1
a就是要求的逆元
LL exgcd(LL a,LL b,LL &x,LL &y)//扩展欧几里得算法
{
if(b==0)
{
x=1,y=0;
return a;
}
LL ret=exgcd(b,a%b,y,x);
y-=a/b*x;
return ret;
}
LL getInv(LL a,LL mod)//求a在mod下的逆元,不存在逆元返回-1
{
LL x,y;
LL d=exgcd(a,mod,x,y);
return d==1?(x%mod+mod)%mod:-1;
}
P是模数,i是待求的逆元,我们求的是 i − 1 {i^{-1}} i−1在mod P意义下的值
p=k*i+r,若(rk=p/i,r=p%i
k * i+r ≡ \equiv ≡ 1 (mod p)
两边同时除以i*r
, k ∗ r − 1 + i − 1 ≡ 0 ( m o d P ) {k*r^{-1}+i^{-1} \equiv 0 (mod P) } k∗r−1+i−1≡0(modP)
移项得: i − 1 ≡ − k ∗ r − 1 ( m o d P ) {i^{-1} \equiv -k*r^{-1} (mod P) } i−1≡−k∗r−1(modP)
即: i − 1 ≡ − p / i {i^{-1} \equiv -p/i} i−1≡−p/i * inv[i % mod p]
边界条件是 inv[1]=1
LL inv[mod+5];
void getInv(LL mod)
{
inv[1]=1;
for(int i=2;i<mod;i++)
inv[i]=(mod-mod/i)*inv[mod%i]%mod;
}