求组合数的几种方法总结

版权声明:希望能在自己成长的道路上帮到更多的人,欢迎各位评论交流 https://blog.csdn.net/yiqzq/article/details/81877160

杨辉三角求组合数

时间复杂度 O ( n 2 ) ,空间复杂度 O ( n 2 )

ll C[N][N];
//C[n][m]就是C(n,m)
void init(int N) {
    for (int i = 0; i < N; i ++) {
        C[i][0] = C[i][i] = 1;
        for (int j = 1; j < i; j ++) {
            C[i][j] = C[i - 1][j] + C[i - 1][j - 1];
            C[i][j] %= mod;
        }
    }
}

逆元求组合数

ll fac[maxn]; //求阶乘
void init(int N) {
    fac[0] = fac[1] = 1;
    for (ll i = 2; i <= N; i++)
        fac[i] = (fac[i - 1] * i) % mod;
}
ll fast_pow(ll a, ll b) {
    ll ans = 1;
    a = a % mod;
    while (b) {
        if (b & 1)
            ans = a * ans % mod;
        a = a * a % mod;
        b >>= 1;
    }
    return ans % mod;
}
ll niYuan(ll a, ll b) { //费马小定理求逆元
    return fast_pow(a, b - 2);
}
ll C(ll a, ll b) {//a比b小
    return fac[b] * niYuan(fac[a], mod) % mod * niYuan(fac[b-a], mod) % mod;
}

Lucas求组合数

ll quick_pow(ll a, ll b, ll p) { //p是质数,要求<1e5
    ll ret = 1;
    while (b) {
        if (b & 1) {
            ret = ret * a % p;
        }
        a = a * a % p;
        b >>= 1;
    }
    return ret;
}
ll C(ll n, ll m, ll p) {
    if (m == 0)return 1;
    ll x = 1, y = 1;
    m = min(m, n - m);
    for (int i = 0; i < m; ++i) {
        x = x * (n - i) % p;
        y = y * (m - i) % p;
    }
    return x * quick_pow(y, p - 2, p) % p;
}
ll lucas(ll n, ll m, ll p) { //n大
    if (n < m)return 0;
    if (n < p && m < p) return C(n, m, p);
    return lucas(n % p, m % p, p) * lucas(n / p, m / p, p) % p;
}

ps,求错位重排代码

ll F[maxn];//保存次数
void init() {
    F[0] = 0;
    F[1] = 0;
    F[2] = 1;
    for (int i = 3; i <= 1e4 + 5; i++) {
        F[i] = ((i - 1) * (F[i - 1] + F[i - 2])) % mod;
    }
}

猜你喜欢

转载自blog.csdn.net/yiqzq/article/details/81877160