求组合数

本文介绍了三种在编程中高效求解组合数的方法:1. 通过‘乘一个除一个’的技巧避免除法导致的超时问题,适用于n≤100;2. 利用杨辉三角的性质直接获取组合数;3. 使用逆元大法,但这种方法限于模为质数的情况。

平时在做题的时候经常会用到求组合数,但是一般情况下普通求Cmn\text{C} ^n_mCmn都会超时,这里介绍四种求组合数的方法:

1. 乘一个除一个

一般情况下求组合数的方法都是乘一个除一个
就比如C53=5×4×33×2×1C^3_5 = \frac{5 \times 4 \times 3}{3 \times 2 \times 1}C53=3×2×15×4×3 但是我们顺着做除不尽,所以我们把分母反着看:
C53=5×4×31×2×3=51×42×33=5×2×1C^3_5 = \frac{5\times4\times3}{1\times2\times3} = \frac{5}{1} \times \frac{4}{2} \times \frac{3}{3} = 5 \times2 \times 1C53=1×2×35×4×3=15×24×33=5×2×1

这样就能求出一个组合数了。
适用的数据范围:n⩽100n\leqslant 100n100

2. 杨辉三角

众所周知, 杨辉三角中的AnmA_{nm}Anm=CmnC^n_mCmn

所以只需要把杨辉三角求出来就是这样的:

第0列第1列第2列第3列第4列第5列
第0行1
第1行11
第2行121
第3行1331
第4行14641
第5行15101051

仔细比对一下,AnmA_{nm}Anm是不是等于CnmC_{nm}Cnm,
所以这时候直接输出AnmA_{nm}Anm就行了

3.用逆元大法

但是这种方法有一个限制:模的P必须是质数,比如100000000710000000071000000007,因为我们需要用费马小定理求出逆元。
具体就这么写

#include <bits/stdc++.h>
using namespace std;
#define LL long long int
#define MOD 1000000007
#define MAXN 20000005
LL fac[MAXN], rec[MAXN];
LL qpow(LL a, LL b)
{
	LL res = 1;
	while(b)
	{
		if(b & 1)
			res = res * a % MOD;
		a = a * a % MOD;
		b >>= 1;
	}
	return res;
}
int main()
{
	int n, m;
	scanf("%d %d", &n, &m);
	fac[0] = 1;
	for(int i = 1; i <= n; i++)
	{
		fac[i] = fac[i - 1] * i;
		fac[i] %= MOD;
	}
	rec[n] = qpow(fac[n], MOD - 2);
	for(int i = n - 1; i >= 1; i--)
		rec[i] = rec[i + 1] * ((i + 1) % MOD) % MOD;
	cout << (((fac[n] * rec[m]) % MOD) * rec[n - m]) % MOD; 
	return 0;
}

完结撒花

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值