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

参考文献

逆元打表

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

原理详阅,不再赘述

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;
} 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值