【数论】求组合数的四种方法

组合数的常用公式

1.\; \; \; C_n^m = \frac{A_n^m}{A_m^m}

2.\; \; \; C_n^m = \frac{n!}{m!(n - m)!}

3.\; \; \; C_{n + 1}^m = C_n^m + C_n^{m - 1}

零、纯暴力法

根据第一个公式,将C_n^m的分子和分母求出,再相除即可。

适用范围:n,m较小的情况下。

时间复杂度O(m)

第一种部分代码如下:

for(int i = n; i >= n - m + 1; i--)
    ans *= i;
for(int i = m; i >= 1; i--)
    ans /= i;

第二种部分代码如下:

fz = 1, fm = 1;    // fz表示分子,fm表示分母
for(int i = n, j = 1; j <= m; i--, j++){
    fz *= i;
    fm *= j;
}
ans = fz / fm;

一、杨辉三角法

上面的第三个公式是符合杨辉三角的公式,因此可以使用第三个公式进行预处理题目范围内所有的C_n^m,需要时直接使用即可。

适用范围:n,m大小在10^3左右。

时间复杂度O(n^2)

C++部分代码如下:

// c[n][m]表示从n个元素中取m个的方案数
for(int i= 0; i <= N; i++)
    for(int j = 0; j <= i; j++)
        if(!j) c[i][j] = 1;
        else c[i][j] = c[i - 1][j] + c[i - 1][j - 1];

二、预处理法

先预处理出范围内所有数的阶乘和阶乘逆元,根据第一个公式直接取需要的阶乘和阶乘逆元的值即可。

适用范围:n,m在10^5以内,且取模的数mod为素数时。

时间复杂度O(N \: log \: N)

乘法逆元的求法可以参照本人之前的博客:

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值