Skip to content

Commit

Permalink
refactor: upload
Browse files Browse the repository at this point in the history
  • Loading branch information
Tiphereth-A committed Feb 6, 2025
1 parent 1ea881b commit 46c8a45
Show file tree
Hide file tree
Showing 51 changed files with 1,026 additions and 50 deletions.
3 changes: 3 additions & 0 deletions config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -740,6 +740,9 @@ notebook:
- ball_box_iil: 球与盒(球相同,盒相同,至少装一个球)
code_ext: hpp
test_ext: cpp
- factl_helper: 大数阶乘与阶乘逆辅助类
code_ext: hpp
test_ext: cpp
nt:
- euler_phi_u32: Euler 函数(32 位)
code_ext: hpp
Expand Down
14 changes: 7 additions & 7 deletions src/code/comb/binom.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,25 @@

namespace tifa_libs::math {

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 { this->reset(max_m + 1); }
template <class mint, class fact = fact_helper<mint>>
requires std::same_as<mint, TPN fact::val_t>
struct binom {
CEXPE binom(u32 max_m = fact::DEFUALT_MAX) NE { fact::ensure(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) * this->get_ifact(n); }
CEXP mint mCn(uint_c auto m, uint_c auto n) CNE { return m < n ? 0 : mPn(m, n) * fact::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)); }
//! mint::mod() must be prime
template <int_c T>
CEXP mint lucas(T m, T n) CNE {
assert(mint::mod() > 1);
auto f = [this](auto &&f, auto m, auto n) NE -> mint { return n == 0 ? 1 : this->mCn(m % mod(), n % mod()) * f(f, m / mod(), n / mod()); };
auto f = [this](auto &&f, auto m, auto n) NE -> mint { return n == 0 ? 1 : this->mCn(m % fact::mod(), n % fact::mod()) * f(f, m / fact::mod(), n / fact::mod()); };
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 : this->get_fact(m) * this->get_ifact(m - n); }
CEXP mint mPn(uint_c auto m, uint_c auto n) CNE { return m < n ? 0 : fact::get_fact(m) * fact::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
39 changes: 24 additions & 15 deletions src/code/comb/fact_helper.hpp
Original file line number Diff line number Diff line change
@@ -1,37 +1,46 @@
#ifndef TIFALIBS_COMB_FACT_HELPER
#define TIFALIBS_COMB_FACT_HELPER

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

namespace tifa_libs::math {

template <class mint>
template <mint_c mint>
struct fact_helper {
using val_t = mint;
static CEXP u32 DEFUALT_MAX = 10'000'001;
static CEXP u64 mod() NE { return mint::mod(); }
static inline vec<mint> fact, ifact;

CEXP void reset(u32 n = DEFUALT_MAX) NE {
if (n = std::min((u32)mod(), n); n < fact.size()) {
fact.resize(n), ifact.resize(n);
return;
}
fact = gen_fact<mint>(n), ifact = gen_ifact<mint>(n);
static CEXP u64 mod() NE { return val_t::mod(); }
static inline vec<val_t> fact, ifact;

fact_helper() = delete;

// ensure fact.size() >= sz
static CEXP void ensure(u32 sz = DEFUALT_MAX) NE {
if (sz = std::max(2_u32, std::min((u32)mod(), sz)); sz <= fact.size()) return;
u32 pre = (u32)fact.size();
fact.resize(sz), ifact.resize(sz);
if (pre < 2) pre = 2, fact[0] = fact[1] = ifact[0] = ifact[1] = 1;
flt_ (u32, i, pre, sz) fact[i] = fact[i - 1] * i;
ifact.back() = fact.back().inv();
for (u32 i = sz - 1; i > pre; --i) ifact[i - 1] = ifact[i] * i;
}

CEXP mint get_fact(u64 n) CNE {
static CEXP val_t get_fact(u64 n) NE {
if (n >= mod()) [[unlikely]]
return 0;
if (fact.empty()) [[unlikely]]
ensure();
if (n < fact.size()) [[likely]]
return fact[n];
mint _ = fact.back() * n;
val_t _ = fact.back() * n;
flt_ (u64, i, fact.size(), n) _ *= i;
return _;
}
CEXP mint get_ifact(u64 n) CNE {
static CEXP val_t get_ifact(u64 n) NE {
if (n >= mod()) [[unlikely]]
return 0;
if (fact.empty()) [[unlikely]]
ensure();
if (n < ifact.size()) [[likely]]
return ifact[n];
return get_fact(n).inv();
Expand Down
82 changes: 82 additions & 0 deletions src/code/comb/factl_helper.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
#ifndef TIFALIBS_COMB_FACTL_HELPER
#define TIFALIBS_COMB_FACTL_HELPER

#include "../poly/ctsh_fps.hpp"
#include "fact_helper.hpp"

namespace tifa_libs::math {

template <class poly_t>
struct factl_helper {
using val_t = TPN poly_t::val_t;
using base_t = fact_helper<TPN poly_t::val_t>;
static CEXP u32 threshold = 2'000'001;

factl_helper() = delete;

static CEXP val_t get_fact(u64 n) NE {
if (n >= base_t::mod()) [[unlikely]]
return 0;
if (base_t::fact.empty()) [[unlikely]]
base_t::ensure(threshold);
if (n < threshold) return base_t::fact[n];
return fact_(n);
}
static CEXP val_t get_ifact(u64 n) NE {
if (n >= base_t::mod()) [[unlikely]]
return 0;
if (base_t::fact.empty()) [[unlikely]]
base_t::ensure(threshold);
if (n < threshold) return base_t::ifact[n];
return fact_(n).inv();
}

private:
static CEXP u32 LBSZ = 9;
static CEXP u32 SZ = 1 << LBSZ;
static inline u64 B = base_t::mod() >> LBSZ;
// f[i] = (i*B + 1) * ... * (i*B + B)
static inline poly_t f{1};
static val_t fact_(u64 n) NE {
static bool inited = false;
if (!inited) {
inited = true;
f.reserve(SZ);
flt_ (u32, i, 0, LBSZ) {
poly_t g = ctsh_fps(f, val_t(1 << i), base_t::ifact, 3_u32 << i);
const auto get = [&](u32 j) { return j < (1_u32 << i) ? f[j] : g[j - (1 << i)]; };
f.resize(2_u32 << i);
flt_ (u32, j, 0, 2_u32 << i) f[j] = get(2 * j) * get(2 * j + 1) * ((2 * j + 1) << i);
}
if (B > SZ) {
vec<val_t> g = ctsh_fps(f, val_t(SZ), base_t::ifact, u32(B - SZ));
std::ranges::move(g, std::back_inserter(f));
} else f.resize(B);
flt_ (u32, i, 0, (u32)B) f[i] *= val_t(i + 1) * SZ;
f.insert(f.begin(), 1);
flt_ (u32, i, 0, (u32)B) f[i + 1] *= f[i];
}
val_t res;
u64 q = n / SZ;
u32 r = n % SZ;
if (2 * r <= SZ) {
res = f[q];
flt_ (u32, i, 0, r) res *= n - i;
} else if (q != B) {
res = f[q + 1];
val_t den = 1;
flt_ (u32, i, 1, SZ - r + 1) den *= n + i;
res /= den;
} else {
res = base_t::mod() - 1;
val_t den = 1;
for (u64 i = base_t::mod() - 1; i > n; --i) den *= i;
res /= den;
}
return res;
}
};

} // namespace tifa_libs::math

#endif
4 changes: 2 additions & 2 deletions src/code/comb/gen_ball_box_ii.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@
namespace tifa_libs::math {

// f = \\prod_{i=1}^m 1/(1-x^i), deg(f) = n
template <class poly>
CEXP poly gen_ball_box_ii(u32 m, u32 n, spnuu inv) NE {
template <class poly, class T>
CEXP poly gen_ball_box_ii(u32 m, u32 n, vec<T> CR inv) NE {
poly f(n + 1);
flt_ (u32, i, 1, m + 1)
flt_ (u32, k, 1, n / i + 1) f[i * k] += inv[k];
Expand Down
4 changes: 2 additions & 2 deletions src/code/comb/gen_bernoulli.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
namespace tifa_libs::math {

// bernoulli[i] = B_i, i=0,1,...,n
template <class poly, std::same_as<TPN poly::val_t> mint>
CEXP poly gen_bernoulli(u32 n, vec<mint> CR fact, vec<mint> CR ifact) NE {
template <class poly, class T, std::same_as<TPN poly::val_t> mint>
CEXP poly gen_bernoulli(u32 n, vec<T> CR fact, vec<T> CR ifact) NE {
if (!n) return poly{1};
poly b(n + 1);
flt_ (u32, i, 0, n + 1) b[i] = ifact[i + 1];
Expand Down
4 changes: 2 additions & 2 deletions src/code/comb/gen_stirling1_col.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
namespace tifa_libs::math {

// stirling1[i] = {i \\brack k}, i=0,1,...,n
template <class poly, bool with_sgn = true>
CEXP poly gen_stirling1_col(u32 n, u32 k, spnuu fact, spnuu inv, spnuu invfact) NE {
template <class poly, class T, bool with_sgn = true>
CEXP poly gen_stirling1_col(u32 n, u32 k, vec<T> CR fact, vec<T> CR inv, vec<T> CR invfact) NE {
if (n < k) return poly(n + 1);
poly f(n + 1);
flt_ (u32, i, 1, n + 1) f[i] = inv[i];
Expand Down
4 changes: 2 additions & 2 deletions src/code/comb/gen_stirling1_row.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
namespace tifa_libs::math {

// stirling1[i] = {n \\brace i}, i=0,1,...,n
template <class poly, bool with_sgn = true>
CEXP poly gen_stirling1_row(u32 n, spnuu fact, spnuu ifact) NE {
template <class poly, class T, bool with_sgn = true>
CEXP poly gen_stirling1_row(u32 n, vec<T> CR fact, vec<T> CR ifact) NE {
using mint = TPN poly::val_t;
if (!n) return poly{1};
poly f{0, 1};
Expand Down
4 changes: 2 additions & 2 deletions src/code/comb/gen_stirling2_col.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,8 @@
namespace tifa_libs::math {

// stirling2[i] = {i \\brack k}, i=0,1,...,n
template <class poly>
CEXP poly gen_stirling2_col(u32 n, u32 k, spnuu fact, spnuu ifact) NE {
template <class poly, class T>
CEXP poly gen_stirling2_col(u32 n, u32 k, vec<T> CR fact, vec<T> CR ifact) NE {
using mint = TPN poly::val_t;
if (k > n) return poly(n + 1);
auto g = [&](auto&& g, poly& f, u32 n) NE -> void {
Expand Down
6 changes: 2 additions & 4 deletions src/code/comb/qbinom.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,20 +6,18 @@

namespace tifa_libs::math {

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

static CEXP u64 mod() NE { return mint::mod(); }
CEXPE qbinom(u32 q, u32 max_m = fact<mint>::DEFUALT_MAX) NE : binom<mint, fact>(max_m), qfact(2) {
CEXPE qbinom(u32 q, u32 max_m = fact::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);
this->reset(max_m / ((u32)qfact.size() - 1) + 2);
}

// $\binom{m}{n}_q$
Expand Down
4 changes: 2 additions & 2 deletions src/code/poly/comp_fpssps.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@
namespace tifa_libs::math {

// @return $f(g(x_0, \dots, x_{n-1}))$
template <class poly, u32 N = 21>
auto comp_fpssps(u32 n, poly f, vec<TPN poly::val_t> g, spnuu fact, spnuu ifact) NE {
template <class poly, class T, u32 N = 21>
auto comp_fpssps(u32 n, poly f, vec<TPN poly::val_t> g, vec<T> CR fact, vec<T> CR ifact) NE {
using mint = TPN poly::val_t;
static conv_subset<mint, N> ss;
if (assert(n <= N); !f.size()) return vec<mint>(1 << n);
Expand Down
4 changes: 2 additions & 2 deletions src/code/poly/compinv_fps.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@
namespace tifa_libs::math {

// @return g s.t. $g(f(x)) \equiv x \pmod{\deg(f)+1}$
template <template <class... Ts> class ccore, class mint, class... args>
CEXP auto compinv_fps(poly<ccore, mint, args...> CR f, spnuu inv, u32 n = 0) NE {
template <template <class... Ts> class ccore, class mint, class T, class... args>
CEXP auto compinv_fps(poly<ccore, mint, args...> CR f, vec<T> CR inv, u32 n = 0) NE {
using poly_t = poly<ccore, mint, args...>;
if (assert(f.size() > 1 && f[0] == 0 && f[1] != 0); !n) n = (u32)f.size();
if (n < 2) return poly_t{0, f[1].inv()}.pre(n);
Expand Down
4 changes: 2 additions & 2 deletions src/code/poly/ctsh_fps.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@

namespace tifa_libs::math {

template <template <class... Ts> class ccore, class mint, class... args>
CEXP poly<ccore, mint, args...> ctsh_fps(poly<ccore, mint, args...> CR f, mint c, spnuu ifact, u32 m = 0) NE {
template <template <class... Ts> class ccore, class mint, class T, class... args>
CEXP poly<ccore, mint, args...> ctsh_fps(poly<ccore, mint, args...> CR f, mint c, vec<T> CR ifact, u32 m = 0) NE {
using poly_t = poly<ccore, mint, args...>;
const u32 n = (u32)f.size(), k = n - 1;
if (!m) m = n;
Expand Down
4 changes: 2 additions & 2 deletions src/code/poly/exp_fpssp.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@

namespace tifa_libs::math {

template <template <class... Ts> class ccore, class mint, class... args>
CEXP auto exp_fpssp(poly<ccore, mint, args...> CR p, spnuu inv, u32 n = 0) NE {
template <template <class... Ts> class ccore, class mint, class T, class... args>
CEXP auto exp_fpssp(poly<ccore, mint, args...> CR p, vec<T> CR inv, u32 n = 0) NE {
if (!p.size()) return p;
if (assert(p[0] == 0); !n) n = (u32)p.size();
polysp<mint> ps = poly2sp(p, n);
Expand Down
4 changes: 2 additions & 2 deletions src/code/poly/ln_fpssp.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@

namespace tifa_libs::math {

template <template <class... Ts> class ccore, class mint, class... args>
CEXP auto ln_fpssp(poly<ccore, mint, args...> CR p, spnuu inv, u32 n = 0) NE {
template <template <class... Ts> class ccore, class mint, class T, class... args>
CEXP auto ln_fpssp(poly<ccore, mint, args...> CR p, vec<T> CR inv, u32 n = 0) NE {
if (assert(!p.empty() && p[0] == 1); !n) n = (u32)p.size();
auto ps = poly2sp(p, n);
poly<ccore, mint, args...> g(n);
Expand Down
4 changes: 2 additions & 2 deletions src/code/poly/pow_fpssp.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@

namespace tifa_libs::math {

template <template <class... Ts> class ccore, class mint, class... args>
CEXP auto pow_fpssp(poly<ccore, mint, args...> CR p, u64 y, spnuu inv, u32 n = 0) NE {
template <template <class... Ts> class ccore, class mint, class T, class... args>
CEXP auto pow_fpssp(poly<ccore, mint, args...> CR p, u64 y, vec<T> CR inv, u32 n = 0) NE {
if (!n) n = (u32)p.size();
if (!y) return poly<ccore, mint, args...>{1}.pre(n);
if (p.is_zero()) return p.pre(n);
Expand Down
4 changes: 2 additions & 2 deletions src/code/poly/tsh_fps.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,8 @@

namespace tifa_libs::math {

template <template <class... Ts> class ccore, class mint, class... args>
CEXP auto tsh_fps(poly<ccore, mint, args...> CR f, mint c, spnuu fact, spnuu ifact) NE {
template <template <class... Ts> class ccore, class mint, class T, class... args>
CEXP auto tsh_fps(poly<ccore, mint, args...> CR f, mint c, vec<T> CR fact, vec<T> CR ifact) NE {
const u32 n = (u32)f.size();
if (n == 1) return f;
poly<ccore, mint, args...> s = f, p((u32)f.size());
Expand Down
4 changes: 4 additions & 0 deletions src/doc_md/comb/factl_helper.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
title: factl_helper
documentation_of: //src/code/comb/factl_helper.hpp
---
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
#define AUTO_GENERATED
#define PROBLEM "https://judge.yosupo.jp/problem/factorial"

#include "../../code/comb/factl_helper.hpp"

CEXP u32 MOD = 998244353;

#define GENTCs_p3ntts30s
#define GENTCs_p3ntts63s
#define GENTCs_p3ntts30d_0
#define GENTCs_p3ntts63d_0
#define GENTCs_pmtts
#define GENTCs_pmttd0
#define GENTCs_pntt

int main() {
#define GENTCs_p3ntts30d_1
#define GENTCs_p3ntts63d_1
#define GENTCs_pmttd1
std::cin.tie(nullptr)->std::ios::sync_with_stdio(false);
u32 t;
std::cin >> t;
while (t--) {
u32 n;
std::cin >> n;
std::cout << tifa_libs::math::factl_helper<poly>::get_fact(n) << '\n';
}
return 0;
}
Loading

0 comments on commit 46c8a45

Please sign in to comment.