模板汇总——逆元
转自仓鼠大神的博客
1.快速幂求法
费马小定理(a和p互质)
a^(p-1) ≡1 (mod p)
a^(p-2) ≡ inv(a) (mod p)
1 LL pow_mod(LL a, LL b, LL p){//a的b次方求余p 2 LL ret = 1; 3 while(b){ 4 if(b & 1) ret = (ret * a) % p; 5 a = (a * a) % p; 6 b >>= 1; 7 } 8 return ret; 9 } 10 LL Fermat(LL a, LL p){//费马求a关于b的逆元 11 return pow_mod(a, p-2, p); 12 }
2.扩展欧几里德算法
1 #include<cstdio> 2 #define LL long long 3 void ex_gcd(LL a, LL b, LL &x, LL &y, LL &d){ 4 if (!b) {d = a, x = 1, y = 0;} 5 else{ 6 ex_gcd(b, a % b, y, x, d); 7 y -= x * (a / b); 8 } 9 } 10 LL inv(LL t, LL p){//如果不存在,返回-1 11 LL d, x, y; 12 ex_gcd(t, p, x, y, d); 13 return d == 1 ? (x % p + p) % p : -1; 14 } 15 int main(){ 16 LL a, p; 17 while(~scanf("%lld%lld", &a, &p)){ 18 printf("%lld\n", inv(a, p)); 19 } 20 }
3.递推法
在O(n)的复杂度内算出n个数的逆元(p需要为质数)
1 #include<cstdio> 2 const int N = 200000 + 5; 3 const int MOD = (int)1e9 + 7; 4 int inv[N]; 5 int init(){ 6 inv[1] = 1; 7 for(int i = 2; i < N; i ++){ 8 inv[i] = (MOD - MOD / i) * 1ll * inv[MOD % i] % MOD; 9 } 10 } 11 int main(){ 12 init(); 13 }
4.组合数逆元
1 int F[N], Finv[N], inv[N];/// F是阶层 Finv是逆元的阶层 2 void init(){ 3 inv[1] = 1; 4 for(int i = 2; i < N; i++) 5 inv[i] = (mod - mod/i) * 1ll * inv[mod % i] % mod; 6 F[0] = Finv[0] = 1; 7 for(int i = 1; i < N; i++){ 8 F[i] = F[i-1] * 1ll * i % mod; 9 Finv[i] = Finv[i-1] * 1ll * inv[i] % mod; 10 } 11 } 12 int comb(int n, int m){ /// C(n,m) 13 if(m < 0 || m > n) return 0; 14 return F[n] * 1ll * Finv[n-m] % mod * Finv[m] % mod; 15 }