Skip to content

Commit

Permalink
refactor: fact_helper
Browse files Browse the repository at this point in the history
  • Loading branch information
Tiphereth-A committed Feb 5, 2025
1 parent 093293d commit 7e4b903
Show file tree
Hide file tree
Showing 8 changed files with 67 additions and 23 deletions.
15 changes: 9 additions & 6 deletions config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -644,6 +644,15 @@ notebook:
code_ext: hpp
test_ext: cpp
comb:
- gen_fact: 阶乘模序列
code_ext: hpp
test_ext: cpp
- gen_ifact: 阶乘逆模序列
code_ext: hpp
test_ext: cpp
- fact_helper: 阶乘与阶乘逆辅助类
code_ext: hpp
test_ext: cpp
- binom: 二项式系数
code_ext: hpp
test_ext: cpp
Expand Down Expand Up @@ -674,12 +683,6 @@ notebook:
- gen_partition: 划分数序列
code_ext: hpp
test_ext: cpp
- gen_fact: 阶乘模序列
code_ext: hpp
test_ext: cpp
- gen_ifact: 阶乘逆模序列
code_ext: hpp
test_ext: cpp
- gen_inv: 逆元序列
code_ext: hpp
test_ext: cpp
Expand Down
17 changes: 7 additions & 10 deletions src/code/comb/binom.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,17 @@
#define TIFALIBS_COMB_BINOM

#include "../util/traits.hpp"
#include "gen_fact.hpp"
#include "gen_ifact.hpp"
#include "fact_helper.hpp"

namespace tifa_libs::math {

template <class mint>
struct binom {
vec<mint> fact, ifact;

static CEXP u64 mod() NE { return mint::mod(); }
CEXPE binom(u32 max_m = 0) NE : fact(gen_fact<mint>(std::min((u32)mod(), max_m + 1))), ifact(gen_ifact<mint>(std::min((u32)mod(), max_m + 1))) {}
template <class mint, template <class> class fact = fact_helper>
struct binom : fact<mint> {
static CEXP auto mod() NE { return fact<mint>::mod(); }
CEXPE binom(u32 max_m = fact<mint>::DEFUALT_MAX) NE : fact<mint>(std::min((u32)mod(), max_m + 1)) {}

// $\binom{m}{n}$
CEXP mint mCn(uint_c auto m, uint_c auto n) CNE { return m < n ? 0 : mPn(m, n) * ifact[(usz)n]; }
CEXP mint mCn(uint_c auto m, uint_c auto n) CNE { return m < n ? 0 : mPn(m, n) * this->get_ifact(n); }
// $\binom{m}{n}$
template <sint_c T>
CEXP mint mCn(T m, T n) CNE { return m < n || n < 0 ? 0 : mCn(to_uint_t<T>(m), to_uint_t<T>(n)); }
Expand All @@ -27,7 +24,7 @@ struct binom {
return m < n || n < 0 ? 0 : f(f, to_uint_t<T>(m), to_uint_t<T>(n));
}
// $\binom{m}{n} \cdot n!$
CEXP mint mPn(uint_c auto m, uint_c auto n) CNE { return m < n ? 0 : fact[(usz)m] * ifact[(usz)(m - n)]; }
CEXP mint mPn(uint_c auto m, uint_c auto n) CNE { return m < n ? 0 : this->get_fact(m) * this->get_ifact(m - n); }
// $\binom{m}{n} \cdot n!$
template <sint_c T>
CEXP mint mPn(T m, T n) CNE { return m < n || n < 0 ? 0 : mPn(to_uint_t<T>(m), to_uint_t<T>(n)); }
Expand Down
42 changes: 42 additions & 0 deletions src/code/comb/fact_helper.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
#ifndef TIFALIBS_COMB_FACT_HELPER
#define TIFALIBS_COMB_FACT_HELPER

#include "gen_fact.hpp"
#include "gen_ifact.hpp"

namespace tifa_libs::math {

template <class mint>
struct fact_helper {
static CEXP u32 DEFUALT_MAX = 10'000'001;
static CEXP u64 mod() NE { return mint::mod(); }
static inline vec<mint> fact = gen_fact<mint>(DEFUALT_MAX),
ifact = gen_ifact<mint>(DEFUALT_MAX);
CEXPE fact_helper(u32 n = 0) NE {
if (u32 _ = std::min((u32)mod(), n); _ > fact.size()) [[unlikely]] {
fact = gen_fact<mint>(_);
ifact = gen_ifact<mint>(_);
}
}

CEXP mint get_fact(u64 n) CNE {
if (n >= mod()) [[unlikely]]
return 0;
if (n < fact.size()) [[likely]]
return fact[n];
mint _ = fact.back() * n;
flt_ (u64, i, fact.size(), n) _ *= i;
return _;
}
CEXP mint get_ifact(u64 n) CNE {
if (n >= mod()) [[unlikely]]
return 0;
if (n < ifact.size()) [[likely]]
return ifact[n];
return get_fact(n).inv();
}
};

} // namespace tifa_libs::math

#endif
10 changes: 4 additions & 6 deletions src/code/comb/qbinom.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,28 +6,26 @@

namespace tifa_libs::math {

template <class mint>
struct qbinom {
template <class mint, template <class> class fact = fact_helper>
struct qbinom : binom<mint, fact> {
vec<mint> qfact, iqfact;
binom<mint> b;

static CEXP u64 mod() NE { return mint::mod(); }
CEXPE qbinom(u32 max_m, u32 q) NE : qfact(2) {
CEXPE qbinom(u32 q, u32 max_m = fact<mint>::DEFUALT_MAX) NE : binom<mint, fact>(max_m), qfact(2) {
assert(q), qfact[0] = qfact[1] = 1;
mint x = 1;
flt_ (u32, i, 2, max_m + 1)
if ((x = x * q + 1).val()) qfact.push_back(x);
else break;
flt_ (u32, i, 3, (u32)qfact.size()) qfact[i] *= qfact[i - 1];
iqfact = gen_invseq(qfact);
b = binom<mint>(u32((max_m + qfact.size() - 2) / (qfact.size() - 1)));
}

// $\binom{m}{n}_q$
CEXP mint qmCn(uint_c auto m, uint_c auto n) CNE {
if (m < n) return 0;
if (m < qfact.size()) return qfact[(usz)m] * iqfact[(usz)n] * iqfact[(usz)(m - n)];
return b.mCn(m / qfact.size(), n / qfact.size()) * qmCn(m % qfact.size(), n % qfact.size());
return this->mCn(m / qfact.size(), n / qfact.size()) * qmCn(m % qfact.size(), n % qfact.size());
}
// $\binom{m}{n}_q$
template <sint_c T>
Expand Down
4 changes: 4 additions & 0 deletions src/doc_md/comb/fact_helper.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
title: fact_helper
documentation_of: //src/code/comb/fact_helper.hpp
---
Empty file.
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ int main() {
}
return 0;
}
tifa_libs::math::qbinom<mint> mCn(std::min(MOD - 1, 10'000'000_u32), q);
tifa_libs::math::qbinom<mint> mCn(q);
while (t--) {
i64 n, k;
tifa_libs::fin >> n >> k;
Expand Down
Empty file.

0 comments on commit 7e4b903

Please sign in to comment.