chenfy27的刷题记录

导航

luoguP3807 P为1E6以内质数的组合数

有T次询问,每次给出整数n,m,p,计算C(n+m,n)%p的值。输入保证p为质数。
1<=n,m,p<=1E5; 1<=T<=10

n很大,p为百万级以内的质数,并且需要多次求组合数时,一般用lucas定理来计算组合数:lucas(n,k,p) = lucas(n/p,k/p,p) * C(n%p,k%p,p)

#include <bits/stdc++.h>
using i64 = long long;

const int Z = 100005;
i64 fac[Z], ifac[Z];
int power(int a, int b, int p) {
    i64 r = 1, t = a;
    while (b) {
        if (b & 1) r = r * t % p;
        t = t * t % p;
        b /= 2;
    }
    return r % p;
}
int comb(int n, int k, int p) {
    if (k > n) return 0;
    return fac[n] * ifac[k] % p * ifac[n - k] % p;
}
int lucas(int n, int k, int p) {
    if (k == 0) return 1;
    return lucas(n / p, k / p, p) * comb(n % p, k % p, p) % p;
}
void solve() {
    int n, m, p;
    std::cin >> n >> m >> p;
    fac[0] = 1;
    for (int i = 1; i < p; i++) {
        fac[i] = fac[i - 1] * i % p;
    }
    ifac[p - 1] = power(fac[p - 1], p - 2, p);
    for (int i = p - 2; i >= 0; i--) {
        ifac[i] = ifac[i + 1] * (i + 1) % p;
    }
    std::cout << lucas(n + m, n, p) << "\n";
}

int main() {
    std::cin.tie(0)->sync_with_stdio(0);
    int t = 1;
    std::cin >> t;
    while (t--) solve();
    return 0;
}

posted on 2024-03-10 20:20  chenfy27  阅读(33)  评论(0)    收藏  举报