From 32fc223db30f1744e0aa21e17e746afba7ce5c9e Mon Sep 17 00:00:00 2001 From: Luke Videckis Date: Sun, 7 Sep 2025 15:15:17 -0600 Subject: [PATCH 1/8] add single function for mod division --- library/math/mod_division.hpp | 8 +++++++ library/math/mod_int.hpp | 12 ----------- library/math/mod_int_division.hpp | 9 -------- library/math/mod_int_pow.hpp | 12 ----------- .../handmade_tests/mod_division.test.cpp | 21 +++++++++++++++++++ 5 files changed, 29 insertions(+), 33 deletions(-) create mode 100644 library/math/mod_division.hpp delete mode 100644 library/math/mod_int.hpp delete mode 100644 library/math/mod_int_division.hpp delete mode 100644 library/math/mod_int_pow.hpp create mode 100644 tests/library_checker_aizu_tests/handmade_tests/mod_division.test.cpp diff --git a/library/math/mod_division.hpp b/library/math/mod_division.hpp new file mode 100644 index 00000000..c1c3ee2b --- /dev/null +++ b/library/math/mod_division.hpp @@ -0,0 +1,8 @@ +#pragma once +const int mod = 998244353; +int mod_div(int x, int y) { + int m = mod, u = 1, v = 0; + while (m) swap(u -= y / m * v, v), swap(y %= m, m); + assert(y == 1); + return 1LL * x * (u + mod) % mod; +} diff --git a/library/math/mod_int.hpp b/library/math/mod_int.hpp deleted file mode 100644 index a2fa8818..00000000 --- a/library/math/mod_int.hpp +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once -const int mod = 998244353; -//! https://github.com/kth-competitive-programming/kactl/blob/main/content/number-theory/ModularArithmetic.h -//! https://codeforces.com/blog/entry/122714 -struct mint { - int x; - mint(int xx = 0): x(xx < 0 ? xx + mod : xx) {} - mint operator+(mint b) { return x - mod + b.x; } - mint operator-(mint b) { return x - b.x; } - mint operator*(mint b) { return ll(x) * b.x % mod; } -#include "mod_int_division.hpp" -}; diff --git a/library/math/mod_int_division.hpp b/library/math/mod_int_division.hpp deleted file mode 100644 index a043afe4..00000000 --- a/library/math/mod_int_division.hpp +++ /dev/null @@ -1,9 +0,0 @@ -#pragma once -mint operator/(mint b) { - int m = mod, u = 1, v = 0; - while (m) - u = exchange(v, u - b.x / m * v), - b.x = exchange(m, b.x % m); - assert(b.x == 1); - return *this * u; -} diff --git a/library/math/mod_int_pow.hpp b/library/math/mod_int_pow.hpp deleted file mode 100644 index ecfe501c..00000000 --- a/library/math/mod_int_pow.hpp +++ /dev/null @@ -1,12 +0,0 @@ -#pragma once -#include "mod_int.hpp" -//! https://github.com/kth-competitive-programming/kactl/blob/main/content/number-theory/ModPow.h -//! returns (b^e)%mod, 1 for 0^0. -//! @time O(log e) -//! @space O(1) -mint mpow(mint b, ll e) { - mint res = 1; - for (; e; e /= 2, b = b * b) - if (e & 1) res = res * b; - return res; -} diff --git a/tests/library_checker_aizu_tests/handmade_tests/mod_division.test.cpp b/tests/library_checker_aizu_tests/handmade_tests/mod_division.test.cpp new file mode 100644 index 00000000..b4e0b429 --- /dev/null +++ b/tests/library_checker_aizu_tests/handmade_tests/mod_division.test.cpp @@ -0,0 +1,21 @@ +#define PROBLEM \ + "https://onlinejudge.u-aizu.ac.jp/problems/ITP1_1_A" +#include "../template.hpp" +#define const ; +#include "../../../library/math/mod_division.hpp" +#undef const +int main() { + cin.tie(0)->sync_with_stdio(0); + for (mod = 1; mod < 500; mod++) { + for (int x = 0; x < mod; x++) { + for (int y = 0; y < mod; y++) { + if (gcd(y, mod) == 1) { + int quotient = mod_div(x, y); + assert(1LL * quotient * y % mod == x); + } + } + } + } + cout << "Hello World\n"; + return 0; +} From 8884bac3c9f2cbd20606e6f75704ce44733193c9 Mon Sep 17 00:00:00 2001 From: GitHub Date: Sun, 7 Sep 2025 21:16:22 +0000 Subject: [PATCH 2/8] [auto-verifier] verify commit 32fc223db30f1744e0aa21e17e746afba7ce5c9e --- .verify-helper/timestamps.remote.json | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/.verify-helper/timestamps.remote.json b/.verify-helper/timestamps.remote.json index 48921319..2d14f6ed 100644 --- a/.verify-helper/timestamps.remote.json +++ b/.verify-helper/timestamps.remote.json @@ -40,7 +40,6 @@ "tests/library_checker_aizu_tests/data_structures/persistent_seg_tree.test.cpp": "2024-12-05 10:41:42 -0600", "tests/library_checker_aizu_tests/data_structures/pq_ds_undo_sliding_window.test.cpp": "2025-02-10 14:50:36 -0700", "tests/library_checker_aizu_tests/data_structures/pq_ds_undo_with_dsu.test.cpp": "2025-02-10 14:50:36 -0700", -"tests/library_checker_aizu_tests/data_structures/range_parallel_dsu.test.cpp": "2025-08-28 13:19:16 -0600", "tests/library_checker_aizu_tests/data_structures/rmq_disjoint_sparse_table.test.cpp": "2024-12-15 14:34:10 -0600", "tests/library_checker_aizu_tests/data_structures/rmq_linear.test.cpp": "2025-08-14 12:01:15 -0600", "tests/library_checker_aizu_tests/data_structures/rmq_sparse_table.test.cpp": "2025-08-14 12:01:15 -0600", @@ -65,20 +64,18 @@ "tests/library_checker_aizu_tests/graphs/hopcroft_karp_aizu.test.cpp": "2025-08-14 10:27:46 -0600", "tests/library_checker_aizu_tests/graphs/hopcroft_karp_lib_checker.test.cpp": "2025-08-14 10:27:46 -0600", "tests/library_checker_aizu_tests/graphs/mst.test.cpp": "2025-08-22 13:27:42 -0600", -"tests/library_checker_aizu_tests/graphs/offline_incremental_scc.test.cpp": "2025-08-28 13:19:16 -0600", "tests/library_checker_aizu_tests/graphs/strongly_connected_components_aizu.test.cpp": "2025-08-14 10:27:46 -0600", "tests/library_checker_aizu_tests/graphs/strongly_connected_components_lib_checker.test.cpp": "2025-08-14 10:27:46 -0600", "tests/library_checker_aizu_tests/graphs/two_edge_components.test.cpp": "2025-08-14 10:27:46 -0600", "tests/library_checker_aizu_tests/handmade_tests/count_paths.test.cpp": "2025-08-28 13:57:36 -0600", "tests/library_checker_aizu_tests/handmade_tests/dsu.test.cpp": "2025-08-22 13:14:15 -0600", "tests/library_checker_aizu_tests/handmade_tests/dsu_size.test.cpp": "2024-12-14 19:50:29 -0600", -"tests/library_checker_aizu_tests/handmade_tests/edge_cd_small_trees.test.cpp": "2025-08-28 13:19:16 -0600", "tests/library_checker_aizu_tests/handmade_tests/fib_matrix_expo.test.cpp": "2025-08-28 13:19:16 -0600", "tests/library_checker_aizu_tests/handmade_tests/functional_graph.test.cpp": "2025-08-06 16:18:37 -0600", "tests/library_checker_aizu_tests/handmade_tests/manacher.test.cpp": "2024-12-14 19:50:29 -0600", "tests/library_checker_aizu_tests/handmade_tests/merge_st_and_wavelet.test.cpp": "2025-08-04 17:01:28 -0600", "tests/library_checker_aizu_tests/handmade_tests/mobius.test.cpp": "2025-02-10 14:50:36 -0700", -"tests/library_checker_aizu_tests/handmade_tests/mod_int.test.cpp": "2025-08-28 13:19:16 -0600", +"tests/library_checker_aizu_tests/handmade_tests/mod_division.test.cpp": "2025-09-07 15:15:17 -0600", "tests/library_checker_aizu_tests/handmade_tests/n_choose_k.test.cpp": "2025-08-28 13:19:16 -0600", "tests/library_checker_aizu_tests/handmade_tests/permutation_tree_small.test.cpp": "2025-08-14 12:01:15 -0600", "tests/library_checker_aizu_tests/handmade_tests/rmq_small_n.test.cpp": "2025-08-14 12:01:15 -0600", @@ -89,21 +86,14 @@ "tests/library_checker_aizu_tests/loops/quotients.test.cpp": "2024-11-17 14:04:03 -0600", "tests/library_checker_aizu_tests/loops/submasks.test.cpp": "2025-02-10 14:50:36 -0700", "tests/library_checker_aizu_tests/loops/supermasks.test.cpp": "2025-02-10 14:50:36 -0700", -"tests/library_checker_aizu_tests/math/binary_exponentiation_mod.test.cpp": "2025-08-28 13:19:16 -0600", "tests/library_checker_aizu_tests/math/binary_matrix_mult.test.cpp": "2024-11-17 14:04:03 -0600", "tests/library_checker_aizu_tests/math/count_paths.test.cpp": "2025-08-28 13:19:16 -0600", "tests/library_checker_aizu_tests/math/derangement.test.cpp": "2024-11-17 14:04:03 -0600", -"tests/library_checker_aizu_tests/math/matrix_determinant.test.cpp": "2025-08-28 13:19:16 -0600", "tests/library_checker_aizu_tests/math/matrix_mult.test.cpp": "2024-11-17 14:04:03 -0600", -"tests/library_checker_aizu_tests/math/mod_int_derangement.test.cpp": "2025-08-28 13:19:16 -0600", -"tests/library_checker_aizu_tests/math/mod_int_gcd_convolution.test.cpp": "2025-08-28 13:19:16 -0600", -"tests/library_checker_aizu_tests/math/mod_int_n_choose_k.test.cpp": "2025-08-28 13:19:16 -0600", -"tests/library_checker_aizu_tests/math/mod_int_tetration.test.cpp": "2025-08-28 13:19:16 -0600", "tests/library_checker_aizu_tests/math/n_choose_k.test.cpp": "2025-08-28 13:19:16 -0600", "tests/library_checker_aizu_tests/math/num_subsequences.test.cpp": "2024-11-17 14:04:03 -0600", "tests/library_checker_aizu_tests/math/partitions.test.cpp": "2025-08-28 13:19:16 -0600", "tests/library_checker_aizu_tests/math/prime_sieve.test.cpp": "2024-11-22 11:54:52 -0600", -"tests/library_checker_aizu_tests/math/solve_linear_mod.test.cpp": "2025-08-28 13:19:16 -0600", "tests/library_checker_aizu_tests/math/tetration.test.cpp": "2024-11-17 14:04:03 -0600", "tests/library_checker_aizu_tests/math/totient.test.cpp": "2024-11-17 14:04:03 -0600", "tests/library_checker_aizu_tests/math/xor_basis.test.cpp": "2025-08-04 20:35:27 -0600", @@ -133,7 +123,6 @@ "tests/library_checker_aizu_tests/trees/edge_cd_contour_range_query.test.cpp": "2025-08-14 10:27:46 -0600", "tests/library_checker_aizu_tests/trees/edge_cd_contour_range_update.test.cpp": "2025-08-14 10:27:46 -0600", "tests/library_checker_aizu_tests/trees/edge_cd_count_paths_per_length.test.cpp": "2025-08-14 10:27:46 -0600", -"tests/library_checker_aizu_tests/trees/edge_cd_reroot_dp.test.cpp": "2025-08-28 13:19:16 -0600", "tests/library_checker_aizu_tests/trees/hld_aizu1.test.cpp": "2025-08-24 19:27:23 -0600", "tests/library_checker_aizu_tests/trees/hld_aizu2.test.cpp": "2025-08-24 19:27:23 -0600", "tests/library_checker_aizu_tests/trees/hld_lib_checker_path.test.cpp": "2025-08-24 19:27:23 -0600", @@ -145,6 +134,5 @@ "tests/library_checker_aizu_tests/trees/lca_all_methods_aizu.test.cpp": "2025-08-21 12:17:27 -0600", "tests/library_checker_aizu_tests/trees/lca_all_methods_lib_checker.test.cpp": "2025-08-21 12:17:27 -0600", "tests/library_checker_aizu_tests/trees/shallowest_aizu_tree_height.test.cpp": "2025-09-03 10:32:09 -0600", -"tests/library_checker_aizu_tests/trees/shallowest_lib_checker_tree_path_composite.test.cpp": "2025-09-03 10:32:09 -0600", "tests/library_checker_aizu_tests/trees/subtree_isomorphism.test.cpp": "2025-08-14 10:27:46 -0600" } \ No newline at end of file From 787504013d0b25983745dfab77f7c5bae4c196c7 Mon Sep 17 00:00:00 2001 From: Luke Videckis Date: Sun, 7 Sep 2025 15:27:41 -0600 Subject: [PATCH 3/8] fixed some tests --- .../range_parallel_dsu.test.cpp | 31 ++++---- .../graphs/offline_incremental_scc.test.cpp | 14 ++-- .../edge_cd_small_trees.test.cpp | 5 +- .../handmade_tests/mod_int.test.cpp | 72 ------------------- .../math/binary_exponentiation_mod.test.cpp | 16 ----- .../math/mod_int_derangement.test.cpp | 20 ------ .../math/mod_int_gcd_convolution.test.cpp | 1 - .../math/mod_int_n_choose_k.test.cpp | 9 +-- .../math/mod_int_tetration.test.cpp | 5 -- ...t_lib_checker_tree_path_composite.test.cpp | 45 +++++++----- 10 files changed, 52 insertions(+), 166 deletions(-) delete mode 100644 tests/library_checker_aizu_tests/handmade_tests/mod_int.test.cpp delete mode 100644 tests/library_checker_aizu_tests/math/binary_exponentiation_mod.test.cpp delete mode 100644 tests/library_checker_aizu_tests/math/mod_int_derangement.test.cpp diff --git a/tests/library_checker_aizu_tests/data_structures/range_parallel_dsu.test.cpp b/tests/library_checker_aizu_tests/data_structures/range_parallel_dsu.test.cpp index d9e05292..af7a24cd 100644 --- a/tests/library_checker_aizu_tests/data_structures/range_parallel_dsu.test.cpp +++ b/tests/library_checker_aizu_tests/data_structures/range_parallel_dsu.test.cpp @@ -4,23 +4,19 @@ #include "../template.hpp" #include "../../../library/data_structures/dsu/range_parallel_dsu.hpp" #include "../../../library/data_structures/dsu/range_parallel_equivalence_classes.hpp" -#include "../../../library/math/mod_int.hpp" +const int mod = 998244353; int main() { cin.tie(0)->sync_with_stdio(0); int n, q; cin >> n >> q; rp_dsu dsu(n); - vector y(n); - for (int i = 0; i < n; i++) { - int num; - cin >> num; - y[i] = num; - } - vector x = y; - mint ans = 0; + vi y(n); + for (int i = 0; i < n; i++) cin >> y[i]; + vi x = y; + int ans = 0; auto f = [&](int u, int v) { - ans = ans + x[u] * x[v]; - x[u] = x[u] + x[v]; + ans = (ans + 1LL * x[u] * x[v]) % mod; + x[u] = (x[u] + x[v]) % mod; }; vector> queries; queries.reserve(q); @@ -29,18 +25,19 @@ int main() { cin >> k >> a >> b; dsu.join(a, b, k, f); queries.push_back({a, b, k}); - cout << ans.x << '\n'; + cout << ans << '\n'; if (qq == 0 || qq == 1 || qq == 10 || qq == 1000 || qq == 100'000 || qq == q - 1) { auto uf = get_rp_dsu(queries, n); - vector sums(n); - mint offline_ans = 0; + vi sums(n); + int offline_ans = 0; for (int i = 0; i < n; i++) { int id = uf.find(i); - offline_ans = offline_ans + sums[id] * y[i]; - sums[id] = sums[id] + y[i]; + offline_ans = + (offline_ans + 1LL * sums[id] * y[i]) % mod; + sums[id] = (sums[id] + y[i]) % mod; } - assert(ans.x == offline_ans.x); + assert(ans == offline_ans); } } return 0; diff --git a/tests/library_checker_aizu_tests/graphs/offline_incremental_scc.test.cpp b/tests/library_checker_aizu_tests/graphs/offline_incremental_scc.test.cpp index ce8a932a..7edac3e1 100644 --- a/tests/library_checker_aizu_tests/graphs/offline_incremental_scc.test.cpp +++ b/tests/library_checker_aizu_tests/graphs/offline_incremental_scc.test.cpp @@ -3,13 +3,13 @@ #include "../template.hpp" #include "../../../library/graphs/strongly_connected_components/offline_incremental_scc.hpp" #include "../../../library/data_structures/dsu/dsu.hpp" -#include "../../../library/math/mod_int.hpp" +const int mod = 998244353; int main() { cin.tie(0)->sync_with_stdio(0); int n, m; cin >> n >> m; - vector xs(n); - for (int i = 0; i < n; i++) cin >> xs[i].x; + vector xs(n); + for (int i = 0; i < n; i++) cin >> xs[i]; vector> eds(m); for (auto& [u, v] : eds) cin >> u >> v; auto joins = offline_incremental_scc(eds, n); @@ -21,7 +21,7 @@ int main() { ranges::sort(all(order), {}, [&](int i) { return joins[i]; }); DSU dsu(n); - mint sum = 0; + int sum = 0; for (int t = 0, it = 0; t < m; t++) { while (it < m && joins[order[it]] <= t) { auto [u, v] = eds[order[it]]; @@ -29,14 +29,14 @@ int main() { v = dsu.go(v); if (dsu.e[u] > dsu.e[v]) swap(u, v); if (u != v) { - sum = sum + xs[u] * xs[v]; - xs[u] = xs[u] + xs[v]; + sum = (sum + 1LL * xs[u] * xs[v]) % mod; + xs[u] = (xs[u] + xs[v]) % mod; xs[v] = xs[u]; } dsu.join(u, v); it++; } - cout << sum.x << '\n'; + cout << sum << '\n'; } return 0; } diff --git a/tests/library_checker_aizu_tests/handmade_tests/edge_cd_small_trees.test.cpp b/tests/library_checker_aizu_tests/handmade_tests/edge_cd_small_trees.test.cpp index df92f5e3..e8c20167 100644 --- a/tests/library_checker_aizu_tests/handmade_tests/edge_cd_small_trees.test.cpp +++ b/tests/library_checker_aizu_tests/handmade_tests/edge_cd_small_trees.test.cpp @@ -3,7 +3,6 @@ #include "../template.hpp" #include "../edge_cd_asserts.hpp" #include "../../../kactl/stress-tests/utilities/genTree.h" -#include "../../../library/math/mod_int_pow.hpp" #include "../../../library/trees/edge_cd.hpp" int main() { { @@ -21,7 +20,9 @@ int main() { }); } for (int n = 2; n <= 7; n++) { - int num_codes = mpow(n, n - 2).x; + int num_codes = 1; + for (int k = 0; k < n - 2; k++) num_codes *= n; + // int num_codes = mpow(n, n - 2).x; vector> pruf_codes(num_codes, vector(n - 2)); for (int i = 0; i < num_codes; i++) { diff --git a/tests/library_checker_aizu_tests/handmade_tests/mod_int.test.cpp b/tests/library_checker_aizu_tests/handmade_tests/mod_int.test.cpp deleted file mode 100644 index 4520bab2..00000000 --- a/tests/library_checker_aizu_tests/handmade_tests/mod_int.test.cpp +++ /dev/null @@ -1,72 +0,0 @@ -#define PROBLEM \ - "https://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=ITP1_1_A" -#include "../template.hpp" -#include "../../../library/contest/random.hpp" -#include "../../../kactl/content/number-theory/euclid.h" -// trick to remove const so I can use arbitrary prime mode -// here -#define const ; -#include "../../../library/math/mod_int_pow.hpp" -#undef const -int main() { - cin.tie(0)->sync_with_stdio(0); - mint val; - assert(val.x == 0); - vector mods = {1, 4, 998'244'353, 1'000'000'007}; - for (int i = 0; i < 1'000'000; i++) { - int type = rnd(0, 5); - if (type == 0) { - mod = mods[rnd(0, int(sz(mods)) - 1)]; - val = rnd(-mod + 1, mod - 1); - assert(0 <= val.x && val.x < mod); - } else if (type == 1) { - int to_add = rnd(-mod + 1, mod - 1); - int prev_val = val.x; - val = val + mint(to_add); - assert( - val.x == (1LL * prev_val + to_add + mod) % mod); - } else if (type == 2) { - int to_sub = rnd(-mod + 1, mod - 1); - int prev_val = val.x; - val = val - mint(to_sub); - assert( - val.x == (1LL * prev_val - to_sub + mod) % mod); - } else if (type == 3) { - int to_mult = rnd(-mod + 1, mod - 1); - int prev_val = val.x; - val = val * mint(to_mult); - assert( - val.x == (1LL * prev_val * (to_mult + mod)) % mod); - } else if (type == 4) { - if (mod == 1 || mod == 4) continue; - int to_divide = rnd(1, mod - 1); - int prev_val = val.x; - val = val / mint(to_divide); - assert( - val.x == (mpow(to_divide, mod - 2) * prev_val).x); - } else { - assert(type == 5); - int pow = rnd(0, 20); - int prev_val = val.x; - int naive = 1; - for (int j = 0; j < pow; j++) - naive = 1LL * naive * prev_val % mod; - val = mpow(val, pow); - assert(val.x == naive); - if (mod == 1 && pow == 0) val.x %= mod; - } - assert(0 <= val.x && val.x < mod); - } - for (mod = 1; mod < 300; mod++) { - for (int init = 0; init < mod; init++) { - ll x, y; - ll gcd = euclid(init, mod, x, y); - assert(x * init + y * mod == gcd); - assert(-mod / gcd < x && x < mod / gcd); - if (gcd == 1) - assert((mint(1) / init).x == mint(x).x); - } - } - cout << "Hello World\n"; - return 0; -} diff --git a/tests/library_checker_aizu_tests/math/binary_exponentiation_mod.test.cpp b/tests/library_checker_aizu_tests/math/binary_exponentiation_mod.test.cpp deleted file mode 100644 index 211821ce..00000000 --- a/tests/library_checker_aizu_tests/math/binary_exponentiation_mod.test.cpp +++ /dev/null @@ -1,16 +0,0 @@ -#define PROBLEM \ - "https://onlinejudge.u-aizu.ac.jp/courses/library/6/NTL/all/NTL_1_B" -#include "../template.hpp" -// trick to remove const so I can use arbitrary prime mode -// here -#define const ; -#include "../../../library/math/mod_int_pow.hpp" -#undef const -int main() { - cin.tie(0)->sync_with_stdio(0); - mod = 1'000'000'007; - int m, n; - cin >> m >> n; - cout << mpow(m, n).x << '\n'; - return 0; -} diff --git a/tests/library_checker_aizu_tests/math/mod_int_derangement.test.cpp b/tests/library_checker_aizu_tests/math/mod_int_derangement.test.cpp deleted file mode 100644 index 3ccb9ad6..00000000 --- a/tests/library_checker_aizu_tests/math/mod_int_derangement.test.cpp +++ /dev/null @@ -1,20 +0,0 @@ -#define PROBLEM \ - "https://judge.yosupo.jp/problem/montmort_number_mod" -#include "../template.hpp" -// trick to remove const so I can use arbitrary prime mode -// here -#define const ; -#include "../../../library/math/mod_int.hpp" -#undef const -int main() { - cin.tie(0)->sync_with_stdio(0); - int n; - cin >> n >> mod; - vector dp(n + 1); - dp[0] = 1; - for (int i = 2; i <= n; i++) - dp[i] = (dp[i - 1] + dp[i - 2]) * (i - 1); - for (int i = 1; i <= n; i++) cout << dp[i].x << " "; - cout << '\n'; - return 0; -} diff --git a/tests/library_checker_aizu_tests/math/mod_int_gcd_convolution.test.cpp b/tests/library_checker_aizu_tests/math/mod_int_gcd_convolution.test.cpp index f7c93ea5..c4978eb4 100644 --- a/tests/library_checker_aizu_tests/math/mod_int_gcd_convolution.test.cpp +++ b/tests/library_checker_aizu_tests/math/mod_int_gcd_convolution.test.cpp @@ -1,7 +1,6 @@ #define PROBLEM \ "https://judge.yosupo.jp/problem/gcd_convolution" #include "../template.hpp" -#include "../../../library/math/mod_int.hpp" istream& operator>>(istream& is, vector& v) { for (int i = 1; i < sz(v); i++) is >> v[i]; return is; diff --git a/tests/library_checker_aizu_tests/math/mod_int_n_choose_k.test.cpp b/tests/library_checker_aizu_tests/math/mod_int_n_choose_k.test.cpp index aa019a3c..c9027a45 100644 --- a/tests/library_checker_aizu_tests/math/mod_int_n_choose_k.test.cpp +++ b/tests/library_checker_aizu_tests/math/mod_int_n_choose_k.test.cpp @@ -1,17 +1,12 @@ #define PROBLEM \ "https://judge.yosupo.jp/problem/binomial_coefficient_prime_mod" #include "../template.hpp" -// trick to remove const so I can use arbitrary prime mode -// here -#define const ; -#include "../../../library/math/mod_int.hpp" -#undef const int main() { cin.tie(0)->sync_with_stdio(0); - int t; + int t, mod; cin >> t >> mod; const int mx_n = min(int(1e7), mod); - vector fact(mx_n, 1); + vector fact(mx_n, 1); for (int i = 2; i < mx_n; i++) fact[i] = fact[i - 1] * i; vector inv_fact(mx_n, 1); inv_fact.back() = mint(1) / fact.back(); diff --git a/tests/library_checker_aizu_tests/math/mod_int_tetration.test.cpp b/tests/library_checker_aizu_tests/math/mod_int_tetration.test.cpp index 3ece33ad..451f6733 100644 --- a/tests/library_checker_aizu_tests/math/mod_int_tetration.test.cpp +++ b/tests/library_checker_aizu_tests/math/mod_int_tetration.test.cpp @@ -2,11 +2,6 @@ "https://judge.yosupo.jp/problem/tetration_mod" #include "../template.hpp" #include "../../../library/math/totient.hpp" -// trick to remove const so I can use arbitrary prime mode -// here -#define const ; -#include "../../../library/math/mod_int_pow.hpp" -#undef const int mod_int_tetration(int b, int e, int local_mod) { if (local_mod == 1) return 0; if (b == 0) return (e + 1) % 2 % local_mod; diff --git a/tests/library_checker_aizu_tests/trees/shallowest_lib_checker_tree_path_composite.test.cpp b/tests/library_checker_aizu_tests/trees/shallowest_lib_checker_tree_path_composite.test.cpp index 6c115054..fbc6c7aa 100644 --- a/tests/library_checker_aizu_tests/trees/shallowest_lib_checker_tree_path_composite.test.cpp +++ b/tests/library_checker_aizu_tests/trees/shallowest_lib_checker_tree_path_composite.test.cpp @@ -3,18 +3,19 @@ #undef _GLIBCXX_DEBUG #include "../template.hpp" #include "../../../library/trees/shallowest_decomp_tree.hpp" -#include "../../../library/math/mod_int.hpp" -using line = array; +const int mod = 998244353; +using line = array; // returns f(g(x)) = f[0]*(g[0]*x+g[1]) + f[1] line compose(line f, line g) { - return {f[0] * g[0], f[1] + f[0] * g[1]}; + return {int(1LL * f[0] * g[0] % mod), + int((f[1] + 1LL * f[0] * g[1]) % mod)}; } int main() { cin.tie(0)->sync_with_stdio(0); int n; cin >> n; - vector a(n); - for (int i = 0; i < n; i++) cin >> a[i].x; + vector a(n); + for (int i = 0; i < n; i++) cin >> a[i]; vector> adj(n); vector> weight(n); for (int i = 0; i < n - 1; i++) { @@ -25,30 +26,36 @@ int main() { weight[u].push_back({b, c}); weight[v].push_back({b, c}); } - vector res(n); - for (int i = 0; i < n; i++) res[i] = a[i]; + vector res(a); shallowest(adj, [&](int cent) { assert(ssize(adj[cent]) == ssize(weight[cent])); - mint total_sum_evaluated = 0; + int total_sum_evaluated = 0; int total_cnt_nodes = 0; - mint curr_sum_evaluated = 0; + int curr_sum_evaluated = 0; int curr_cnt_nodes = 0; auto dfs = [&](auto&& self, int v, int p, line downwards, line upwards, bool forwards) -> void { // f(x) + f(y) + f(z) = b*x+c + b*y+c + b*z+c = // b*(x+y+z) + c*3 - res[v] = res[v] + upwards[0] * total_sum_evaluated + - upwards[1] * total_cnt_nodes; + res[v] = + (res[v] + 1LL * upwards[0] * total_sum_evaluated + + 1LL * upwards[1] * total_cnt_nodes) % + mod; if (forwards) { - res[v] = - res[v] + upwards[0] * a[cent] + upwards[1]; + res[v] = (res[v] + 1LL * upwards[0] * a[cent] + + upwards[1]) % + mod; res[cent] = - res[cent] + downwards[0] * a[v] + downwards[1]; + (res[cent] + 1LL * downwards[0] * a[v] + + downwards[1]) % + mod; } curr_cnt_nodes++; - curr_sum_evaluated = curr_sum_evaluated + - downwards[0] * a[v] + downwards[1]; + curr_sum_evaluated = + (curr_sum_evaluated + 1LL * downwards[0] * a[v] + + downwards[1]) % + mod; for (int i = 0; i < ssize(adj[v]); i++) { int u = adj[v][i]; line curr_line = weight[v][i]; @@ -64,7 +71,7 @@ int main() { dfs(dfs, adj[cent][i], cent, weight[cent][i], weight[cent][i], 1); total_sum_evaluated = - total_sum_evaluated + curr_sum_evaluated; + (total_sum_evaluated + curr_sum_evaluated) % mod; total_cnt_nodes += curr_cnt_nodes; } total_sum_evaluated = 0; @@ -75,7 +82,7 @@ int main() { dfs(dfs, adj[cent][i], cent, weight[cent][i], weight[cent][i], 0); total_sum_evaluated = - total_sum_evaluated + curr_sum_evaluated; + (total_sum_evaluated + curr_sum_evaluated) % mod; total_cnt_nodes += curr_cnt_nodes; } for (int v : adj[cent]) { @@ -88,6 +95,6 @@ int main() { } } }); - for (int i = 0; i < n; i++) cout << res[i].x << ' '; + for (int i = 0; i < n; i++) cout << res[i] << ' '; cout << '\n'; } From 878dd7187e08b48710c4a5743d076b702bcd0d3c Mon Sep 17 00:00:00 2001 From: Luke Videckis Date: Sun, 7 Sep 2025 15:37:00 -0600 Subject: [PATCH 4/8] more fixes --- .../math/mod_int_gcd_convolution.test.cpp | 28 ----------- .../math/mod_int_n_choose_k.test.cpp | 28 ----------- .../math/mod_int_tetration.test.cpp | 29 ----------- .../trees/edge_cd_reroot_dp.test.cpp | 50 +++++++++++-------- 4 files changed, 28 insertions(+), 107 deletions(-) delete mode 100644 tests/library_checker_aizu_tests/math/mod_int_gcd_convolution.test.cpp delete mode 100644 tests/library_checker_aizu_tests/math/mod_int_n_choose_k.test.cpp delete mode 100644 tests/library_checker_aizu_tests/math/mod_int_tetration.test.cpp diff --git a/tests/library_checker_aizu_tests/math/mod_int_gcd_convolution.test.cpp b/tests/library_checker_aizu_tests/math/mod_int_gcd_convolution.test.cpp deleted file mode 100644 index c4978eb4..00000000 --- a/tests/library_checker_aizu_tests/math/mod_int_gcd_convolution.test.cpp +++ /dev/null @@ -1,28 +0,0 @@ -#define PROBLEM \ - "https://judge.yosupo.jp/problem/gcd_convolution" -#include "../template.hpp" -istream& operator>>(istream& is, vector& v) { - for (int i = 1; i < sz(v); i++) is >> v[i]; - return is; -} -int main() { - cin.tie(0)->sync_with_stdio(0); - int n; - cin >> n; - vector a(n + 1), b(n + 1); - cin >> a >> b; - n++; - vector c(n); - for (int g = n - 1; g >= 1; g--) { - mint sum_a = 0, sum_b = 0; - for (int i = g; i < n; i += g) { - sum_a = sum_a + a[i]; - sum_b = sum_b + b[i]; - c[g] = c[g] - c[i]; - } - c[g] = c[g] + sum_a * sum_b; - } - for (int i = 1; i < n; i++) cout << c[i].x << ' '; - cout << '\n'; - return 0; -} diff --git a/tests/library_checker_aizu_tests/math/mod_int_n_choose_k.test.cpp b/tests/library_checker_aizu_tests/math/mod_int_n_choose_k.test.cpp deleted file mode 100644 index c9027a45..00000000 --- a/tests/library_checker_aizu_tests/math/mod_int_n_choose_k.test.cpp +++ /dev/null @@ -1,28 +0,0 @@ -#define PROBLEM \ - "https://judge.yosupo.jp/problem/binomial_coefficient_prime_mod" -#include "../template.hpp" -int main() { - cin.tie(0)->sync_with_stdio(0); - int t, mod; - cin >> t >> mod; - const int mx_n = min(int(1e7), mod); - vector fact(mx_n, 1); - for (int i = 2; i < mx_n; i++) fact[i] = fact[i - 1] * i; - vector inv_fact(mx_n, 1); - inv_fact.back() = mint(1) / fact.back(); - for (int i = mx_n - 2; i >= 1; i--) - inv_fact[i] = inv_fact[i + 1] * (i + 1); - for (int i = 0; i < mx_n; i++) { - assert((fact[i] * inv_fact[i]).x == 1); - assert(inv_fact[i].x == (mint(1) / fact[i]).x); - } - while (t--) { - int n, k; - cin >> n >> k; - if (k < 0 || k > n) cout << 0 << '\n'; - else - cout << (fact[n] * inv_fact[k] * inv_fact[n - k]).x - << '\n'; - } - return 0; -} diff --git a/tests/library_checker_aizu_tests/math/mod_int_tetration.test.cpp b/tests/library_checker_aizu_tests/math/mod_int_tetration.test.cpp deleted file mode 100644 index 451f6733..00000000 --- a/tests/library_checker_aizu_tests/math/mod_int_tetration.test.cpp +++ /dev/null @@ -1,29 +0,0 @@ -#define PROBLEM \ - "https://judge.yosupo.jp/problem/tetration_mod" -#include "../template.hpp" -#include "../../../library/math/totient.hpp" -int mod_int_tetration(int b, int e, int local_mod) { - if (local_mod == 1) return 0; - if (b == 0) return (e + 1) % 2 % local_mod; - if (b == 1 || e == 0) return 1; - if (e == 1) return b % local_mod; - if (b == 2 && e == 2) return 4 % local_mod; - if (b == 2 && e == 3) return 16 % local_mod; - if (b == 3 && e == 2) return 27 % local_mod; - int t = totient(local_mod); - int exp = mod_int_tetration(b, e - 1, t); - mod = local_mod; - assert(mod != 0); - return mpow(b, exp + t).x; -} -int main() { - cin.tie(0)->sync_with_stdio(0); - int t; - cin >> t; - while (t--) { - int a, b, local_mod; - cin >> a >> b >> local_mod; - cout << mod_int_tetration(a, b, local_mod) << '\n'; - } - return 0; -} diff --git a/tests/library_checker_aizu_tests/trees/edge_cd_reroot_dp.test.cpp b/tests/library_checker_aizu_tests/trees/edge_cd_reroot_dp.test.cpp index 8334678c..b7548c9d 100644 --- a/tests/library_checker_aizu_tests/trees/edge_cd_reroot_dp.test.cpp +++ b/tests/library_checker_aizu_tests/trees/edge_cd_reroot_dp.test.cpp @@ -3,34 +3,34 @@ #include "../template.hpp" #include "../edge_cd_asserts.hpp" #include "../../../library/trees/edge_cd.hpp" -#include "../../../library/math/mod_int.hpp" +const int mod = 998244353; int main() { cin.tie(0)->sync_with_stdio(0); int n; cin >> n; vector a(n); - vector res(n); + vector res(n); for (int i = 0; i < n; i++) { cin >> a[i]; res[i] = a[i]; } vector adj(n); - vector b(n - 1), c(n - 1); + vector b(n - 1), c(n - 1); vector> par(n, {-1, -1}); vector> base_adj(n); { vector>> adj_with_id(n); for (int i = 0; i < n - 1; i++) { int u, v; - cin >> u >> v >> b[i].x >> c[i].x; + cin >> u >> v >> b[i] >> c[i]; adj[u].push_back(v); adj[v].push_back(u); base_adj[u].push_back(v); base_adj[v].push_back(u); adj_with_id[u].emplace_back(v, i); adj_with_id[v].emplace_back(u, i); - res[u] = res[u] + b[i] * a[v] + c[i]; - res[v] = res[v] + b[i] * a[u] + c[i]; + res[u] = (res[u] + 1LL * b[i] * a[v] + c[i]) % mod; + res[v] = (res[v] + 1LL * b[i] * a[u] + c[i]) % mod; } auto dfs = [&](auto&& self, int u) -> void { for (auto [v, e_id] : adj_with_id[u]) @@ -49,17 +49,19 @@ int main() { edge_cd(adj, [&](const vector& cd_adj, int cent, int split) -> void { - array>, 2> all_backwards; - array sum_forward = {0, 0}; + array>, 2> all_backwards; + array sum_forward = {0, 0}; array cnt_nodes = {0, 0}; auto dfs = [&](auto&& self, int u, int p, - array forwards, - array backwards, + array forwards, + array backwards, int side) -> void { all_backwards[side].push_back( {u, backwards[0], backwards[1]}); - sum_forward[side] = sum_forward[side] + - forwards[0] * a[u] + forwards[1]; + sum_forward[side] = + (sum_forward[side] + 1LL * forwards[0] * a[u] + + forwards[1]) % + mod; cnt_nodes[side]++; for (int v : cd_adj[u]) { if (v == p) continue; @@ -67,12 +69,15 @@ int main() { // f(x) = ax+b // g(x) = cx+d // f(g(x)) = a(cx+d)+b = acx+ad+b - array curr_forw = { - forwards[0] * b[e_id], - forwards[0] * c[e_id] + forwards[1]}; - array curr_backw = { - backwards[0] * b[e_id], - backwards[1] * b[e_id] + c[e_id]}; + array curr_forw = { + int(1LL * forwards[0] * b[e_id] % mod), + int( + (1LL * forwards[0] * c[e_id] + forwards[1]) % + mod)}; + array curr_backw = { + int(1LL * backwards[0] * b[e_id] % mod), + int((1LL * backwards[1] * b[e_id] + c[e_id]) % + mod)}; self(self, v, u, curr_forw, curr_backw, side); } }; @@ -84,13 +89,14 @@ int main() { for (int side = 0; side < 2; side++) { for ( auto [u, curr_b, curr_c] : all_backwards[side]) { - res[u.x] = res[u.x] + - curr_b * sum_forward[!side] + - curr_c * cnt_nodes[!side]; + res[u] = + (res[u] + 1LL * curr_b * sum_forward[!side] + + 1LL * curr_c * cnt_nodes[!side]) % + mod; } } }); - for (int i = 0; i < n; i++) cout << res[i].x << ' '; + for (int i = 0; i < n; i++) cout << res[i] << ' '; cout << '\n'; return 0; } From 25d64d3cfe28921144b543b71468641a98f5503d Mon Sep 17 00:00:00 2001 From: Luke Videckis Date: Sun, 7 Sep 2025 15:43:09 -0600 Subject: [PATCH 5/8] another fix --- library/math/matrix_related/row_reduce.hpp | 25 +++++++++++-------- .../math/matrix_related/solve_linear_mod.hpp | 15 ++++++----- .../math/solve_linear_mod.test.cpp | 19 +++++++------- 3 files changed, 30 insertions(+), 29 deletions(-) diff --git a/library/math/matrix_related/row_reduce.hpp b/library/math/matrix_related/row_reduce.hpp index 1ad29ee7..64ac986b 100644 --- a/library/math/matrix_related/row_reduce.hpp +++ b/library/math/matrix_related/row_reduce.hpp @@ -1,5 +1,5 @@ #pragma once -#include "../mod_int.hpp" +#include "../mod_division.hpp" //! @code //! auto [rank, det] = row_reduce(mat, cols); //! @endcode @@ -8,28 +8,31 @@ //! affected by row operations //! @time O(n * m * min(cols, n)) //! @space O(1) -pair row_reduce(vector>& mat, +pair row_reduce(vector>& mat, int cols) { int n = sz(mat), m = sz(mat[0]), rank = 0; - mint det = 1; + int det = 1; for (int col = 0; col < cols && rank < n; col++) { auto it = find_if(rank + all(mat), - [&](auto& v) { return v[col].x; }); + [&](auto& v) { return v[col]; }); if (it == end(mat)) { det = 0; continue; } if (it != begin(mat) + rank) { - det = mint(0) - det; + det = (mod - det) % mod; iter_swap(begin(mat) + rank, it); } - det = det * mat[rank][col]; - mint a_inv = mint(1) / mat[rank][col]; - for (mint& num : mat[rank]) num = num * a_inv; - rep(i, 0, n) if (i != rank && mat[i][col].x != 0) { - mint num = mat[i][col]; + det = 1LL * det * mat[rank][col] % mod; + int a_inv = mod_div(1, mat[rank][col]); + for (int& num : mat[rank]) + num = 1LL * num * a_inv % mod; + rep(i, 0, n) if (i != rank && mat[i][col] != 0) { + int num = mat[i][col]; rep(j, 0, m) mat[i][j] = - mat[i][j] - mat[rank][j] * num; + ((mat[i][j] - 1LL * mat[rank][j] * num) % mod + + mod) % + mod; } rank++; } diff --git a/library/math/matrix_related/solve_linear_mod.hpp b/library/math/matrix_related/solve_linear_mod.hpp index 600f0d1f..d3b78617 100644 --- a/library/math/matrix_related/solve_linear_mod.hpp +++ b/library/math/matrix_related/solve_linear_mod.hpp @@ -11,22 +11,21 @@ //! @time O(n * m * min(n, m)) //! @space O(m) struct solve_linear_mod { - int rank; - mint det; - vector sol; - solve_linear_mod(vector>& mat, - const vector& rhs) { + int rank, det; + vector sol; + solve_linear_mod(vector>& mat, + const vector& rhs) { int n = sz(mat), m = sz(mat[0]); rep(i, 0, n) mat[i].push_back(rhs[i]); tie(rank, det) = row_reduce(mat, m); if (any_of(rank + all(mat), - [](auto& v) { return v.back().x; })) { + [](vi& v) { return v.back(); })) { return; } sol.resize(m); int j = 0; - for_each(begin(mat), begin(mat) + rank, [&](auto& v) { - while (v[j].x == 0) j++; + for_each(begin(mat), begin(mat) + rank, [&](vi& v) { + while (!v[j]) j++; sol[j] = v.back(); }); } diff --git a/tests/library_checker_aizu_tests/math/solve_linear_mod.test.cpp b/tests/library_checker_aizu_tests/math/solve_linear_mod.test.cpp index e12a5765..432d531b 100644 --- a/tests/library_checker_aizu_tests/math/solve_linear_mod.test.cpp +++ b/tests/library_checker_aizu_tests/math/solve_linear_mod.test.cpp @@ -6,11 +6,11 @@ int main() { cin.tie(0)->sync_with_stdio(0); int n, m; cin >> n >> m; - vector> mat(n, vector(m)); + vector> mat(n, vector(m)); for (int i = 0; i < n; i++) - for (int j = 0; j < m; j++) cin >> mat[i][j].x; - vector b(n); - for (int i = 0; i < n; i++) cin >> b[i].x; + for (int j = 0; j < m; j++) cin >> mat[i][j]; + vector b(n); + for (int i = 0; i < n; i++) cin >> b[i]; solve_linear_mod info(mat, b); assert(info.rank <= min(n, m)); if (empty(info.sol)) { @@ -18,21 +18,20 @@ int main() { return 0; } cout << m - info.rank << '\n'; - for (auto val : info.sol) cout << val.x << " "; + for (int val : info.sol) cout << val << " "; cout << '\n'; vector pivot(m, -1); for (int i = 0, j = 0; i < info.rank; i++) { - while (mat[i][j].x == 0) j++; + while (mat[i][j] == 0) j++; pivot[j] = i; } for (int j = 0; j < m; j++) if (pivot[j] == -1) { - vector x(m, 0); - x[j] = -1; - assert(0 <= x[j].x && x[j].x < mod); + vector x(m, 0); + x[j] = mod - 1; for (int k = 0; k < j; k++) if (pivot[k] != -1) x[k] = mat[pivot[k]][j]; - for (int k = 0; k < m; k++) cout << x[k].x << " "; + for (int k = 0; k < m; k++) cout << x[k] << " "; cout << '\n'; } return 0; From 4c759674672354419b3fa1d3f6d153c2493f49bf Mon Sep 17 00:00:00 2001 From: Luke Videckis Date: Sun, 7 Sep 2025 15:45:17 -0600 Subject: [PATCH 6/8] final fix --- .../math/matrix_determinant.test.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/library_checker_aizu_tests/math/matrix_determinant.test.cpp b/tests/library_checker_aizu_tests/math/matrix_determinant.test.cpp index e983f4c3..4421321e 100644 --- a/tests/library_checker_aizu_tests/math/matrix_determinant.test.cpp +++ b/tests/library_checker_aizu_tests/math/matrix_determinant.test.cpp @@ -6,10 +6,10 @@ int main() { cin.tie(0)->sync_with_stdio(0); int n; cin >> n; - vector> matrix(n, vector(n)); + vector> matrix(n, vector(n)); for (int i = 0; i < n; i++) - for (int j = 0; j < n; j++) cin >> matrix[i][j].x; + for (int j = 0; j < n; j++) cin >> matrix[i][j]; auto [rank, det] = row_reduce(matrix, n); - cout << det.x << '\n'; + cout << det << '\n'; return 0; } From 5d6e3a14a1d7979c4067b65e8d598238815ce7e9 Mon Sep 17 00:00:00 2001 From: Luke Videckis Date: Sun, 7 Sep 2025 15:46:00 -0600 Subject: [PATCH 7/8] add KACTL macro --- library/math/matrix_related/row_reduce.hpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/library/math/matrix_related/row_reduce.hpp b/library/math/matrix_related/row_reduce.hpp index 64ac986b..6193b262 100644 --- a/library/math/matrix_related/row_reduce.hpp +++ b/library/math/matrix_related/row_reduce.hpp @@ -8,8 +8,7 @@ //! affected by row operations //! @time O(n * m * min(cols, n)) //! @space O(1) -pair row_reduce(vector>& mat, - int cols) { +pii row_reduce(vector>& mat, int cols) { int n = sz(mat), m = sz(mat[0]), rank = 0; int det = 1; for (int col = 0; col < cols && rank < n; col++) { From 30b988e46aadf077893bf31d299a2caa40c62cef Mon Sep 17 00:00:00 2001 From: Luke Videckis Date: Sun, 7 Sep 2025 15:49:35 -0600 Subject: [PATCH 8/8] add more KACTL macros --- library/math/matrix_related/row_reduce.hpp | 2 +- library/math/matrix_related/solve_linear_mod.hpp | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/library/math/matrix_related/row_reduce.hpp b/library/math/matrix_related/row_reduce.hpp index 6193b262..1019a968 100644 --- a/library/math/matrix_related/row_reduce.hpp +++ b/library/math/matrix_related/row_reduce.hpp @@ -8,7 +8,7 @@ //! affected by row operations //! @time O(n * m * min(cols, n)) //! @space O(1) -pii row_reduce(vector>& mat, int cols) { +pii row_reduce(vector& mat, int cols) { int n = sz(mat), m = sz(mat[0]), rank = 0; int det = 1; for (int col = 0; col < cols && rank < n; col++) { diff --git a/library/math/matrix_related/solve_linear_mod.hpp b/library/math/matrix_related/solve_linear_mod.hpp index d3b78617..a4a0016d 100644 --- a/library/math/matrix_related/solve_linear_mod.hpp +++ b/library/math/matrix_related/solve_linear_mod.hpp @@ -12,9 +12,8 @@ //! @space O(m) struct solve_linear_mod { int rank, det; - vector sol; - solve_linear_mod(vector>& mat, - const vector& rhs) { + vi sol; + solve_linear_mod(vector& mat, const vi& rhs) { int n = sz(mat), m = sz(mat[0]); rep(i, 0, n) mat[i].push_back(rhs[i]); tie(rank, det) = row_reduce(mat, m);