模板汇总——逆元

转自仓鼠大神的博客

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 }
View Code

 

 

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 }
View Code

 

 

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 }
View Code

 

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 }
View Code

 

posted @ 2018-08-23 16:58  Schenker  阅读(229)  评论(0编辑  收藏  举报