逆元
逆元是什么网上有很多资料就不多阐述了.
!主要用于把除法变成乘法!
结论:
a/b%mod=a*(b的逆元)%mod.
比如说一个组合数若是除数或者被除数太大精度就会出问题.这时候就需要通过逆元把除法转换为乘法
费马小定理及欧拉定理
费马小定理: 当mod为素数时a^(mod-1)%mod=1.
左右两边除a变成a^(mod-2)%mod = a^-1.
所以a的逆元就是a^(mod-2).
const int mod=10007;
ll fastpow(ll a,ll b){
if(a==1)return a;
ll ans=1;
for(;b;b>>=1){
if(b&1)ans=ans*a%mod;
a=a*a%mod;
}
return ans;
}
ll Inv(ll a){
return fastpow(a,mod-2);
}
欧拉定理:当a、mod互素,则有a^φ( mod)%mod=1(费马小定理的一般形式)
且a^φ( mod)*a%mod=1
故:a^φ( mod)%mod=a^-1
结论:逆元是a^(φ(mod)−1)
const int mod=10007;
ll fastpow(ll a,ll b){
if(a==1)return a;
ll ans=1;
for(;b;b>>=1){
if(b&1)ans=ans*a%mod;
a=a*a%mod;
}
return ans;
}
ll phi(ll n){
ll ans=n;
for(int i=2;i<=sqrt(n);i++)
if(n % i == 0){
ans = ans / i * (i-1);
while(n%i==0)n/=i;
}
if(n>1)ans=ans/n*(n-1);
return ans;
}
ll Inv(ll a){
return fastpow(a,phi(mod)-1);
}
扩展欧几里得算法
网上抄的:
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(int a,int mod)//求a在mod下的逆元,不存在逆元返回-1
{
LL x,y;
LL d=exgcd(a,mod,x,y);
return d==1?(x%mod+mod)%mod:-1;
}