求组合数 Ⅰ(递推公式)

思路 
 
- 递推法预处理 
  - 利用公式 
- 复杂度 
 
- 利用公式 
- 直接查询 
  - 单次查询复杂度 
 
- 单次查询复杂度 
代码
#include <bits/stdc++.h>
using namespace std;
const int N = 2010;
const int mod = 1e9+7;
int c[N][N];
int get_c(int a, int b)
{
    c[0][0] = 1;
    for(int i = 1; i <= a; i++)
    {
        c[i][0] = 1;
        for(int j = 1; j <= a; j++)
        {
            c[i][j] = (c[i-1][j-1] + c[i-1][j]) % mod;
        }
    }
    
    return c[a][b];
}
int main()
{
    get_c(2000, 2000);
    
    int n;
    cin >> n;
    while (n -- ){
        int a, b;
        cin >> a >> b;
        cout << c[a][b] << '\n';
    }
}求组合数 Ⅱ (乘法逆元、费马小定理、快速幂)

思路 
 
- 很明显,递推法预处理会超时。于是我们选择另一种计算组合数的方式:快速幂(处理分子的阶乘、分母的阶乘) + 费马小定理(将除以分母,在模运算中该换为,乘以分母的乘法逆元) 
  - 步骤        
    - 计算阶乘 
- 快速幂求乘法逆元 ,p = 1e9+7 
 
- 计算阶乘 
- 总复杂度 
- 反思:不同的数据计算阶乘时重复计算了
- 改进:预处理所有阶乘 - (同时可以预处理所有阶乘的乘法逆元)
 
- (同时可以预处理所有阶乘的乘法逆元)
- 注意:求 时 仍不能用除法,要采用乘法逆元 
 
- 步骤        
    
代码
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5+10;
const int mod = 1e9+7;
typedef long long ll;
ll fac[N], ifac[N];
ll qmi(ll base, ll expo)
{
    ll retv = 1;
    while(expo)
    {
        if(expo & 1) retv = retv * base % mod;
        base = base * base % mod;
        expo >>= 1;
    }
    
    return retv;
}
void init()
{
    fac[0] = ifac[0] = 1;
    for(ll i = 1; i <= 100000; i++)
    {
        fac[i] = fac[i-1] * i % mod;
        ifac[i] = qmi(i, mod-2) * ifac[i-1] % mod;
    }
}
int main()
{
    init();
    
    int n;
    cin >> n;
    while (n -- ){
        int a, b;
        cin >> a >> b;
        
        cout << fac[a] * ifac[a-b] % mod * ifac[b] % mod << '\n';
    }
}求组合数 Ⅲ

求组合数 Ⅳ



![LeetCode[中等] 24.两两交换链表中的结点](https://i-blog.csdnimg.cn/direct/baf009bdb4124b7e96e6dc7a6ac292e1.png)
















