C++中组合数可以使用递归或迭代的方式计算。组合数的概念是指从n个不同元素中取出m个元素的方案数,可以表示为C(n,m),也可以表示为n choose m。组合数有以下性质:
- C(n,m) = C(n,n-m)
- C(n,0) = 1
- C(n,n) = 1
- C(n,m) = C(n-1,m-1) + C(n-1,m)
这些性质可以用来简化计算组合数的过程。
在实际应用中,组合数有许多用处。例如:
- 排列组合问题:计算从n个元素中取出m个元素进行排列的方案数。
- 概率论中的组合数:计算从n个元素中任选m个元素的组合中,满足某些条件的方案数。
- 离散数学中的组合数:计算符合某种性质的字符串或序列的方案数。
- 组合优化问题:计算在某些限制条件下,从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、快速幂