逆元(数论倒数)
三种方式求a关于p的逆元(前提:a,p互质)
费马小定理:
inv[a]=a^(p-2)(mod p)
LL fastpow(LL a,LL b,LL p) { a%=p; LL ans=1; while(b>0) { if(b&1)ans=(ans*a)%p; a=(a*a)%p; b>>=1; } return ans; } LL Fermat(LL a,LL p) { return fastpow(a,p-2,p); }
扩展欧几里得:
ax+by=1;
若a,b互质,有解
x就是a关于b的逆元,y就是b关于a的逆元
void exgcd(LL a,LL b,LL x,LL y,LL d) { if(!b) { d=a; x=1; y=0; } else { exgcd(b,a%b,y,x,d); y-=x*(a/b); } } LL getinv(LL a,LL p) { LL x,y,d; exgcd(a,p,x,y,d); return d==1?(x%p+p)%p:-1;//逆元里的求余只能求余成正数,这样可以保证产生0——(p-1)的正数 }
前两种适用于求单个逆元
这一种适用于求0-maxn个数关于p(同一个p)的逆元
当p是个质数的时候有,inv[a]=(p-p/a)*inv[p%a]%p; (a小于p)
const int maxn=1e5+10; const int mod=1e9+7; LL inv[maxn]; void init() { inv[1]=1; for(int i=2;i<maxn;i++) { inv[i]=(LL)(mod-mod/i)*inv[mod%i]%mod; } }