lucas费马逆元组合数求解

#include <iostream>
using namespace std;

const int MOD = 1000000007;  // 模数,通常是大素数
const int MAXN = 100000;     // 设定最大值

long long fact[MAXN + 1];     // 阶乘数组
long long inv_fact[MAXN + 1]; // 逆阶乘数组

// 快速幂算法:计算 (base^exp) % MOD
long long power(long long base, long long exp) {
    long long result = 1;
    while (exp > 0) {
        if (exp % 2 == 1) result = (result * base) % MOD;  // 如果指数是奇数,乘上当前base
        base = (base * base) % MOD;   // 将base自乘,用于计算指数的更高次幂
        exp /= 2;  // 指数右移,等效于 exp //= 2
    }
    return result;
}

// 预处理阶乘和逆阶乘
void precompute(int n) {
    fact[0] = 1;
    for (int i = 1; i <= n; ++i) {
        fact[i] = fact[i - 1] * i % MOD;  // 计算阶乘: fact[i] = i!
    }

    // 计算逆阶乘:利用费马小定理计算 fact[n] 的逆元
    inv_fact[n] = power(fact[n], MOD - 2);  // 计算 fact[n] 的逆元,等价于 fact[n]^(MOD-2) % MOD
    for (int i = n - 1; i >= 0; --i) {
        inv_fact[i] = inv_fact[i + 1] * (i + 1) % MOD;  // 根据 fact[i] 和 fact[i+1] 计算出 inv_fact[i]
    }
}

// 计算组合数 C(n, r) = n! / (r! * (n - r)!)
long long combination(int n, int r) {
    if (r < 0 || r > n) return 0;  // 如果 r 小于 0 或者大于 n,返回 0
    return fact[n] * inv_fact[r] % MOD * inv_fact[n - r] % MOD;  // 计算组合数
}

// Lucas 定理函数
long long lucas(long long n, long long m) {
    if (m == 0) return 1;
    return combination(n % MOD, m % MOD) * lucas(n / MOD, m / MOD) % MOD;//lucas不断递归求可用的组合数 直到为1
}

int main() {
    // 预处理阶乘和逆阶乘
    precompute(MAXN);

    // 示例:计算 C(100000, 50000) % MOD
    long long n = 100000;
    long long m = 50000;
    long long result = lucas(n, m);//调用lucas得到组合数
    cout << "C(" << n << ", " << m << ") % " << MOD << " = " << result << endl;

    return 0;
}
posted @ 2025-02-25 21:53  Qacter  阅读(28)  评论(0)    收藏  举报