[AcWing] 886. 求组合数 II(C++实现)求组合数第二种题型模板题
求组合数有很多种题型,我们需要根据输入的数据的范围来选哪种方式,具体的方式有如下几种:
主要是询问次数和数据大小的不同,对应了不同的解法
此外,另有高精度组合数和卡特兰数两种特例
星号表示本题的思想。
1. 题目
2. 读题(需要重点注意的东西)
思路:
首先,要知道组合数是什么?公式是什么?
一般地,从a个不同的元素中,任取b(b≤a)个元素为一组,叫作从aa个不同元素中取出b个元素的一个组合,这个组合一共有多少组?
公式如下:
由于本题的数据过大,直接计算时间复杂度会很高,因此使用预处理的方式解决:
1、预处理出阶乘
2、预处理出逆元的阶乘(快速幂)
3、由公式求出组合数
附:为什么要采用逆元计算
如果原本的数有除法,但是除法会影响结果,所以采用逆元,将除法转换成乘法;即除以一个数,等于乘以它的逆元。
本题中:
3. 解法
---------------------------------------------------解法---------------------------------------------------
#include <iostream>
#include <algorithm>
using namespace std;
typedef long long LL;
const int N = 100010, mod = 1e9 + 7;
int fact[N], infact[N];
// 快速幂 :求a的k次方模p的结果
int qmi(int a, int k, int p)
{
int res = 1;
while (k)
{
if (k & 1) res = (LL)res * a % p;
a = (LL)a * a % p;
k >>= 1;
}
return res;
}
int main()
{
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;
}
int n;
scanf("%d", &n);
while (n -- )
{
int a, b;
scanf("%d%d", &a, &b);
// 由阶乘和逆元通过公式算出c[a][b]的值
printf("%d\n", (LL)fact[a] * infact[b] % mod * infact[a - b] % mod);
}
return 0;
}
4. 可能有帮助的前置习题
5. 所用到的数据结构与算法思想
- 组合数
- 快速幂求逆元
6. 总结
求组合数第二种题型的模板题,理解思路并背下代码。