求逆元
求逆元
第一种方法:扩展欧几里得法
/*
扩展欧几里得法(求ax+by=gcd)
返回d=gcd(a,b);和对应等式ax+by=d中的x、y
*/
typedef long long ll;
ll extendGcd(ll a,ll b,ll &x,ll &y)
{
if(a==0&&b==0)
{
return -1;
}
if(b==0)
{
x=1;
y=0;
return a;
}
ll d=extendGcd(b,a%b,y,x);
y-=a/b*x;
return d;
}
//求逆元ax=1(mod n)
ll modReverse(ll a,ll n)
{
ll x,y;
ll d=extendGcd(a,n,x,y);
if(d==1)
return (x%n+n)%n;
else
return -1;//表示无逆元
}
第二种方法:简洁写法
/*
求逆元的简洁写法
只能求a<m的情况,且a与m互质
求ax=1(mod m)的x的值,即逆元(0<a<m)
*/
typedef long long ll;
ll inv(ll a,ll m)
{
if(a==1)
return 1;
return inv(m%a,m)*(m-m/a)%m;
}
第三种:欧拉函数求逆元(费马小定理)
/*
欧拉函数法
mod为素数,而且a和m互质
*/
//快速幂取模
ll powM(ll a,ll b,ll m)
{
ll tmp=1;
if(b==0)return 1;
if(b==1)return a%m;
tmp=powM(a,a>>1,m);
tmp=tmp*tmp%m;
if(b&1)
{
tmp=tmp*a%m;
}
return tmp;
}
ll inv(ll a,ll m)
{
return powM(a,m-2,m);
}
第四种:求阶乘逆元
typedef long long ll;
const ll MOD = 1e9 + 7; // 必须为质数才管用
const ll MAXN = 1e5 + 3;
ll fac[MAXN]; // 阶乘
ll inv[MAXN]; // 阶乘的逆元
ll QPow(ll x, ll n)
{
ll ret = 1;
ll tmp = x % MOD;
while (n)
{
if (n & 1)
{
ret = (ret * tmp) % MOD;
}
tmp = tmp * tmp % MOD;
n >>= 1;
}
return ret;
}
void init()
{
fac[0] = 1;
for (int i = 1; i < MAXN; i++)
{
fac[i] = fac[i - 1] * i % MOD;
}
inv[MAXN - 1] = QPow(fac[MAXN - 1], MOD - 2);
for (int i = MAXN - 2; i >= 0; i--)
{
inv[i] = inv[i + 1] * (i + 1) % MOD;
}
}