问题描述:
给定两个整数n和m,要求计算组合数C(n, m)在大模数下的值。由于直接计算可能会导致数值溢出或精度丢失,我们采用乘法逆元的方法来处理除法取余的问题。
思路分析:
为了在模数MOD下计算C(n, m),我们需要使用乘法逆元来替代除法操作。具体来说,C(n, m)可以表示为分子部分(n! / (n-m)!) 与分母部分(m!) 的比值。对于分母部分,我们可以利用乘法逆元将其转换为乘法操作,从而避免直接进行除法。
代码实现:
以下是完整的代码实现,包括必要的头文件、宏定义以及关键函数的定义:
#include
using namespace std;
typedef long long ll;
const int MOD = 1e9 + 7;
// 扩展欧几里得算法求解乘法逆元
ll extended_gcd(ll a, ll b, ll &x, ll &y) {
if (b == 0) {
x = 1;
y = 0;
return a;
}
ll ans = extended_gcd(b, a % b, x, y);
ll temp = x;
x = y;
y = temp - a / b * y;
return ans;
}
// 计算乘法逆元
ll mod_inverse(ll a, ll n) {
ll x, y;
ll d = extended_gcd(a, n, x, y);
if (d == 1)
return (x % n + n) % n;
else
return -1;
}
// 计算组合数C(n, m)
ll combination(ll n, ll m) {
ll ans = 1;
for (ll i = n; i >= n - m + 1; i--) {
ans = (ans * i) % MOD;
}
for (ll i = 1; i <= m; i++) {
ans = (ans * mod_inverse(i, MOD)) % MOD;
}
return ans;
}
int main() {
int t;
cin >> t;
while (t--) {
int n, m;
cin >> n >> m;
if (ncout < }
return 0;
}
上述代码中,我们首先通过扩展欧几里得算法求解乘法逆元,然后利用乘法逆元计算组合数C(n, m)。这种方法不仅提高了计算效率,还确保了结果的准确性。
参考:原始博客链接