扩展欧几里得 逆元 逆元打表

本文介绍了模运算中逆元的概念,并提供了使用扩展欧几里得算法求解逆元的方法。通过递推公式展示了如何快速计算1到n的逆元以及n!的逆元,这些在组合数学计算中尤为重要,如求解组合数。此外,还给出了求解组合数的代码实现,可用于高效计算卡特兰数等组合问题。
摘要由CSDN通过智能技术生成

参考文献

逆元打表

扩展欧几里得+求单个逆元

原理详阅,不再赘述

typedef long long ll;
ll exgcd(ll a,ll b,ll &x,ll &y){//扩展欧几里得算法 ax+by=c 求解a,b 
    if(!b){
        x=1,y=0;
        return a;
    }
    ll ans=exgcd(b,a%b,x,y);
    ll temp=x;
    x=y;
    y=temp-a/b*y;
    return ans;
}
ll inv(ll a,ll p){//求逆元 ax1(mod p)=>a*x+p*y=1 这里我们求x 要求a与p互质,即gcd(a,p)=1 如果不存在返回-1 
	ll x,y,gcd;
	gcd=exgcd(a,p,x,y);
	return (x%p+p)%p;; //x%p+p确保逆元为正数  
} 

逆元打表

一、 1 ~ n 的逆元

递推公式:
inv[i] = ( p - p / i ) * inv[p % i] % p

证明过程:

int inv[N]={0,1};
void invp(int p) {//1 ~ p-1(这里是1~N,那么一定要保证N<p) 模p的逆元 时间复杂度 O(N) inv[i] = (p-p/i) * inv[p%i] % p
	for (i = 2; i <= N; i++) {
		inv[i] = ((p - p/i) * inv[p%i] ) % p;
	}
}

二、n! 的逆元

递推公式:
inv[i] = inv[i + 1] * (i + 1) % MOD

证明过程:

应用:求组合数

原理:
C(n,m) = [ n! / (m! * (n-m)! ) ] % mod
= n! % mod * ([m!]^-1 ) * ( [(n-m)!]^-1) % mod

//求1!~n!的逆元打表  一般用于求组合数 
#include<cstdio>
const int N = 2e6+5;
const int mod = 20100403;
int jc[N];				//阶乘表
int inv[N];				// N! 的逆元!! 注意 下标是i,实际含义是i! 
int n,m;
int power(int a,int n){//快速幂 
	int ans = 1;
	while(n){
		if(n&1)	ans = 1ll * ans * a % mod;
		a = 1ll * a * a % mod;
		n >>= 1;
	}
	return ans;
}
void jiecheng(){//阶乘取模打表 
	jc[0] = 1;
	for(int i = 1;i < N;++i)		jc[i] = 1ll * jc[i-1] * i % mod;
}
void invt(){//逆元打表 
	inv[N-1] = power(jc[N-1],mod-2);
	for(int i = N-2;i >= 0;--i)		inv[i] = (1ll * inv[i+1] * (i+1)) % mod;
} 
int C(int n,int m){//求组合数,n为下标,m为上标 
	int z =  1ll * jc[n] * inv[m] % mod;	
	return  1ll * z * inv[n-m] % mod;
}
int main(){	
	scanf("%d%d",&n,&m);
//	cout<<C(n+m,n)<<endl;
//	cout<<C(n+m,n-1)<<endl;
	// 卡特兰数
	printf("%d\n",(C(n+m,m) - C(n+m,m-1) + mod) % mod);
	return 0;
} 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值