n!, nPr, nCr, nHr 構造体
概要
mod素数での組み合わせを求めるのに使う構造体.
使い方
comb cm()
- 階乗とその逆数を前計算する.デフォルトで mod は 1000000007, 引数の上限は 3000000.
cm.fact(n)
- $n!$
cm.inv_fact(n)
- $(n!)^{-1}$
cm.inv(n)
- $n^{-1}$
cm.pow(n, a)
- $n^a$
cm.perm(n, r)
- $n \times (n-1) \times \dots \times (n-r+1)$
cm.binom(n, r)
- $\binom{n}{r} = n \times (n-1) \times \ldots \times (n-r+1) / r / (r-1) / \dots / 1$
cm.homo(n, r)
- $\binom{n + r - 1}{r}$
実装
template <typename Int, Int MOD, int N>
struct comb_util {
std::array<Int, N + 1> fc, ifc;
comb_util() {
fc[0] = 1;
for (int i = 1; i <= N; i++) fc[i] = fc[i - 1] * i % MOD;
ifc[N] = inv(fc[N]);
for (int i = N - 1; i >= 0; i--) ifc[i] = ifc[i + 1] * (i + 1) % MOD;
}
Int fact(Int n) { return fc[n]; }
Int inv_fact(Int n) { return ifc[n]; }
Int inv(Int n) { return pow(n, MOD - 2); }
Int pow(Int n, Int a) {
Int res = 1, exp = n;
for (; a; a /= 2) {
if (a & 1) res = res * exp % MOD;
exp = exp * exp % MOD;
}
return res;
}
Int perm(Int n, Int r) {
if (r < 0 || n < r)
return 0;
else
return fc[n] * ifc[n - r] % MOD;
}
Int binom(Int n, Int r) {
if (n < 0 || r < 0 || n < r) return 0;
return fc[n] * ifc[r] % MOD * ifc[n - r] % MOD;
}
Int homo(Int n, Int r) {
if (n < 0 || r < 0) return 0;
return r == 0 ? 1 : binom(n + r - 1, r);
}
};
using comb = comb_util<long long, 1000000007, 3000000>;
検証
yukicoder No.117 http://yukicoder.me/submissions/145951