Skip to content

Commit 0fdd7dd

Browse files
编写线性逆元以及用其计算的组合数;release 0.6.0
1 parent 3c92c43 commit 0fdd7dd

3 files changed

Lines changed: 55 additions & 1 deletion

File tree

library/mrpython/modint.hpp

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,28 @@ template <unsigned P> class modint {
7474
return mrpython::fastPow(*this, n);
7575
}
7676
static constexpr unsigned modval() { return P; }
77+
78+
static modint linear_inv(unsigned int n) {
79+
static std::vector<modint<P>> mem = {0, 1};
80+
while (mem.size() <= n) {
81+
unsigned int i = mem.size();
82+
mem.push_back(modint<P>(P - (P / i)) * mem[P % i]);
83+
}
84+
return mem[n];
85+
}
86+
static modint frac_inv(unsigned int n) {
87+
static std::vector<modint<P>> mem = {1};
88+
while (mem.size() <= n) {
89+
unsigned int i = mem.size();
90+
mem.push_back(mem.back() * linear_inv(i));
91+
}
92+
return mem[n];
93+
}
94+
static modint comb(unsigned int n, unsigned int m) {
95+
return n < m ? modint<P>(0)
96+
: frac<modint<P>>(n) * frac_inv(m) * frac_inv(n - m);
97+
}
7798
};
99+
78100
} // namespace mrpython
79101
#endif // MP_LIBRARY_MODINT_HPP

library/test/modint.cpp

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,38 @@ TEST_F(ModIntTest, Power) {
262262
EXPECT_EQ(b.pow(MEDIUM_PRIME - 1).val(), 1);
263263
}
264264

265+
TEST_F(ModIntTest, InverseHelpers) {
266+
// linear_inv should behave like multiplicative inverse on [1, P)
267+
for (unsigned int i = 1; i < SMALL_PRIME; ++i) {
268+
auto inv = modint<SMALL_PRIME>::linear_inv(i);
269+
EXPECT_EQ((inv * modint<SMALL_PRIME>(i)).val(), 1u);
270+
}
271+
272+
// frac_inv is 1 / n!; verify by multiplying forward factorials
273+
modint<SMALL_PRIME> fact = 1;
274+
for (unsigned int i = 0; i <= 8; ++i) {
275+
if (i > 0) fact *= modint<SMALL_PRIME>(i);
276+
auto inv_fact = modint<SMALL_PRIME>::frac_inv(i);
277+
EXPECT_EQ((fact * inv_fact).val(), 1u);
278+
}
279+
}
280+
281+
TEST_F(ModIntTest, Comb) {
282+
// Small Pascal triangle slice to ensure comb matches expected values
283+
const unsigned int n = 8;
284+
for (unsigned int k = 0; k <= n; ++k) {
285+
unsigned int expected = 1;
286+
for (unsigned int i = 1; i <= k; ++i) {
287+
expected = expected * (n - i + 1) / i;
288+
}
289+
EXPECT_EQ(modint<SMALL_PRIME>::comb(n, k).val(), expected % SMALL_PRIME);
290+
}
291+
292+
// Zero and out-of-range cases
293+
EXPECT_EQ(modint<SMALL_PRIME>::comb(0, 0).val(), 1u);
294+
EXPECT_EQ(modint<SMALL_PRIME>::comb(5, 6).val(), 0u);
295+
}
296+
265297
// Test edge cases and miscellaneous functionality
266298
TEST_F(ModIntTest, EdgeCases) {
267299
// Test modval() static method

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "mp-oi-library",
33
"displayName": "mp-oi-library",
44
"description": "Some algorithms and data structures template for competitive programming.",
5-
"version": "0.5.1",
5+
"version": "0.6.0",
66
"repository": "https://github.com/Mr-Python-in-China/mp-oi-library",
77
"license": "LGPL-3.0-only",
88
"author": {

0 commit comments

Comments
 (0)