//逆元小结:
·逆元的定义:
a*x==1(mod p)的解,记作a^(-1),inv(a);
·作用:
计算a/b%p,为了不损失精度,应计算a*b^-1%p;(a*inv(b))%p;
·求逆元
1.快速幂求逆元(p一定要是质数): 单个复杂度O(logn),连续O(nlogn)
根据费马小定理,a,p,互质 ,且p是质数 则有
a^(p-1) == 1 (mod p)
则:
a*a^(p-2) == 1 (mod p)
即a的逆元是a^(p-2)%p;
fact[0]=infact[0]=1;
for(int i=1;i<N;i++)
fact[i]=fact[i-1]*i%p,infact[i]=infact[i-1]*fpow(i,p-2,p)%p;//递推求i!,i!的逆元
2.exgcd求逆元:
走快速幂要求p一定是质数,而exgcd求逆元只需要满足gcd(a,b)==1。
#include<bits/stdc++.h>
using namespace std;
#define int long long
int exgcd(int a,int b,int &x,int &y)
{
if(!b){ x=1,y=0; return a; }
int d=exgcd(b,a%b,y,x);
y-=a/b*x;
return d;
}
signed main()
{
int a,b,x,y; cin>>a>>b;
int d=exgcd(a,b,x,y);
cout<<(d==1?(x+b)%b:-1);
}
3.线性递推逆元: 复杂度O(n)
记i的逆元为inv[i],则有如下递推 :
inv[i]=(p-p/i)*inv[p%i]%p;
注意,线性递推求逆元时,注意将0,1位上赋值为1!!!
·应用:
(1).精确计算a/b%p 的结果
(2).组合数计算
int n,m; cin>>n>>m;
cout<<fact[n]*infact[n-m]%p*infact[m]%p<<endl;
24/8/27 要开学了(*/ω\*)