平时在做题的时候经常会用到求组合数,但是一般情况下普通求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 100n⩽100
2. 杨辉三角
众所周知, 杨辉三角中的AnmA_{nm}Anm=CmnC^n_mCmn(
所以只需要把杨辉三角求出来就是这样的:
| 第0列 | 第1列 | 第2列 | 第3列 | 第4列 | 第5列 | |
|---|---|---|---|---|---|---|
| 第0行 | 1 | |||||
| 第1行 | 1 | 1 | ||||
| 第2行 | 1 | 2 | 1 | |||
| 第3行 | 1 | 3 | 3 | 1 | ||
| 第4行 | 1 | 4 | 6 | 4 | 1 | |
| 第5行 | 1 | 5 | 10 | 10 | 5 | 1 |
仔细比对一下,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;
}
完结撒花
本文介绍了三种在编程中高效求解组合数的方法:1. 通过‘乘一个除一个’的技巧避免除法导致的超时问题,适用于n≤100;2. 利用杨辉三角的性质直接获取组合数;3. 使用逆元大法,但这种方法限于模为质数的情况。
4485

被折叠的 条评论
为什么被折叠?



