c++ 详讲求组合数

C++中组合数可以使用递归或迭代的方式计算。组合数的概念是指从n个不同元素中取出m个元素的方案数,可以表示为C(n,m),也可以表示为n choose m。组合数有以下性质:

  1. C(n,m) = C(n,n-m)
  2. C(n,0) = 1
  3. C(n,n) = 1
  4. C(n,m) = C(n-1,m-1) + C(n-1,m)

这些性质可以用来简化计算组合数的过程。

在实际应用中,组合数有许多用处。例如:

  1. 排列组合问题:计算从n个元素中取出m个元素进行排列的方案数。
  2. 概率论中的组合数:计算从n个元素中任选m个元素的组合中,满足某些条件的方案数。
  3. 离散数学中的组合数:计算符合某种性质的字符串或序列的方案数。
  4. 组合优化问题:计算在某些限制条件下,从n个元素中取出m个元素的方案数,以及求解某些最优解问题。

在编程中,可以使用递归或迭代的方式实现计算组合数。以下为使用递归方式计算组合数的示例代码

long long C(int n, int m) {
    if (m == 0 || m == n) {
        return 1;
    }
    return C(n - 1, m - 1) + C(n - 1, m);
}
 

使用迭代方式计算组合数的示例代码如下:

long long C(int n, int m) {
    long long res = 1;
    m = min(m, n - m);
    for (int i = 0; i < m; ++i) {
        res *= (n - i);
        res /= (i + 1);
    }
    return res;
}
 

这种方式比递归方式更高效,因为递归方式存在大量的重复计算,而迭代方式可以通过记录中间结果来避免重复计算。

题目一:

给定 n 组询问,每组询问给定两个整数 a,b,请你输出 Cbamod(109+7) 的值。

输入格式

第一行包含整数 n。

接下来 n 行,每行包含一组 a 和 b。

输出格式

共 n 行,每行输出一个询问的解。

数据范围

1≤n≤10000
1≤b≤a≤2000

输入样例

3
3 1
5 3
2 2

输出样例

3
10
1

具体代码

#include<iostream>
#include<algorithm>

using namespace std;

const int N=2010,mod=1e9+7;

int c[N][N];

void init()
{
    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])%mod;
        }
    }
}

int main()
{
    int n;
    cin>>n;
    
    init();
    
    while(n--)
    {
        int a,b;
        scanf("%d%d",&a,&b);
        
        printf("%d\n",c[a][b]);
    }
    return 0;
}

思路:第一层循环从底数开始,所以从N开始,第二层循环从i开始,减少时间复杂度,下面那就是一个数学公式

问题二:

给定 n 组询问,每组询问给定两个整数 a,b,请你输出 Cbamod(109+7)的值。

输入格式

第一行包含整数 n。

接下来 n 行,每行包含一组 a 和 b。

输出格式

共 n 行,每行输出一个询问的解。

数据范围

1≤n≤10000
1≤b≤a≤10^5

具体代码

#include<iostream>
#include<algorithm>

using namespace std;

typedef long long LL;

const int N=100010,mod=1e9+7;

int fact[N],infact[N];

int qmi(int a,int b,int p)
{
    int res=1;
    while(b)
    {
        if(b&1) res=(LL)res*a%p;
        a=(LL)a*a%p;
        b>>=1;
    }
    return res;
}

int main()
{
    int n;
    cin>>n;
    
    fact[0]=infact[0]=1;
    for(int i=1;i<N;i++)
    {
        fact[i]=(LL)fact[i-1]*i%mod;
        infact[i]=(LL)infact[i-1]*qmi(i,mod-2,mod)%mod;
    }
    
    while(n--)
    {
        int a,b;
        scanf("%d%d",&a,&b);
        
        printf("%d\n",(LL)fact[a]*infact[b]%mod*infact[a-b]%mod);
    }
    return 0;
}

1、用费马小定理求逆元

2、快速幂

  • 7
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: n); 对于求组合数的问题,可以使用上述公式进行计算。其中,m和k分别代表需要进行组合的元素个数,c(m,k)表示从m个元素中选取k个元素的组合数。 为了计算阶乘值,可以使用如下函数原型: unsigned long fact(unsigned n); 该函数使用迭代法计算无符号整型变量n的阶乘。具体实现可以参考以下代码: unsigned long fact(unsigned n) { unsigned long result = 1; for (unsigned i = 1; i <= n; ++i) { result *= i; } return result; } 使用该函数,可以计算出m!、k!和(m-k)!的值,然后根据组合数公式计算出c(m,k)的值。具体实现可以参考以下代码: unsigned long combination(unsigned m, unsigned k) { unsigned long numerator = fact(m); unsigned long denominator = fact(k) * fact(m - k); return numerator / denominator; } 该函数接受两个参数m和k,返回c(m,k)的值。在函数中,首先使用fact函数计算出m!、k!和(m-k)!的值,然后根据组合数公式计算出c(m,k)的值,并返回结果。 ### 回答2: 组合数指的是从n个元素中选取k个元素的组合情况数,通常用C(n,k)或者(n,k)表示。计算组合数的公式为C(n,k)=n!/k!(n-k)!,其中n!表示n的阶乘,即n!=n×(n-1)×(n-2)×…×1。 为了计算组合数,可以先使用提供的函数原型编写一个计算阶乘的函数fact,并使用该函数计算出n!、k!和(n-k)!,然后带入组合数的公式即可得到C(n,k)的值。 下面是使用C++编写的实现代码: ```c++ /* 函数功能:用迭代法计算无符号整型变量n的阶乘*/ unsigned long fact(unsigned int n) { unsigned long result = 1; for (unsigned int i = 2; i <= n; ++i) { result *= i; } return result; } /* 函数功能:计算组合数C(n,k) */ unsigned long comb(unsigned int n, unsigned int k) { if (k > n) { // k不能大于n return 0; } unsigned long nf = fact(n); // 计算n! unsigned long kf = fact(k); // 计算k! unsigned long nkf = fact(n-k); // 计算(n-k)! return nf / (kf * nkf); // 返回组合数C(n,k)的值 } ``` 在以上代码中,函数fact使用迭代法计算n的阶乘,函数comb接受两个参数n和k,返回组合数C(n,k)的值。在函数comb的实现中,首先进行了参数合法性验证,如果k大于n,则返回0表示不合法。接着调用函数fact计算n!、k!和(n-k)!,最后带入组合数的公式计算出C(n,k)的值,并返回该值。 ### 回答3: 要求计算组合数c(m,k),我们需要先计算出m阶乘、k阶乘、以及(m-k)阶乘的值,然后按照公式c(m,k)=m!/k!(m-k)!进行求解。 在编程过程中,我们可以使用如下函数原型来计算某数的阶乘值: unsigned long fact(unsigned n); 该函数的输入参数n为正整数,返回值为n的阶乘值。 下面是使用以上函数计算组合数的代码实现: unsigned long fact(unsigned n) { unsigned long res = 1; for(unsigned i=2; i<=n; ++i) res *= i; return res; } unsigned long c(unsigned m, unsigned k) { return fact(m) / fact(k) / fact(m-k); } 在函数c中,我们首先调用fact函数分别计算出m、k、(m-k)的阶乘值,然后按照组合数公式进行求解,最终返回求得的值。 需要注意的是,在计算阶乘值时,我们需要使用数据类型unsigned long,因为int类型的范围可能不足以存储较大的阶乘数值。另外,在处理计算值时,我们需要注意保证除法的整除性,因为求出的阶乘数值可能过大,无法精确除尽。为避免该问题,我们可以将分子分母分别分解质因数,保证除法的整除性。 综上所述,求解组合数有着显式的数学公式,使用函数编写程序非常简单。我们只需要设计好阶乘函数的实现方法,按照组合数公式计算即可。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值