TheAlgorithms/C++ 1.0.0
All the algorithms implemented in C++
Loading...
Searching...
No Matches
ncr_modulo_p.cpp
Go to the documentation of this file.
1
12#include <cassert>
13#include <iostream>
14#include <vector>
15
20namespace math {
27namespace ncr_modulo_p {
28
34namespace utils {
44int64_t gcdExtended(const int64_t& a, const int64_t& b, int64_t& x,
45 int64_t& y) {
46 if (a == 0) {
47 x = 0;
48 y = 1;
49 return b;
50 }
51
52 int64_t x1 = 0, y1 = 0;
53 const int64_t gcd = gcdExtended(b % a, a, x1, y1);
54
55 x = y1 - (b / a) * x1;
56 y = x1;
57 return gcd;
58}
59
66int64_t modInverse(const int64_t& a, const int64_t& m) {
67 int64_t x = 0, y = 0;
68 const int64_t g = gcdExtended(a, m, x, y);
69 if (g != 1) { // modular inverse doesn't exist
70 return -1;
71 } else {
72 return ((x + m) % m);
73 }
74}
75} // namespace utils
80 private:
81 const int64_t p = 0;
82 const std::vector<int64_t>
84
92 static std::vector<int64_t> computeFactorialsMod(const int64_t& max_arg_val,
93 const int64_t& mod) {
94 auto res = std::vector<int64_t>(max_arg_val + 1);
95 res[0] = 1;
96 for (int64_t i = 1; i <= max_arg_val; i++) {
97 res[i] = (res[i - 1] * i) % mod;
98 }
99 return res;
100 }
101
102 public:
107 NCRModuloP(const int64_t& size, const int64_t& p)
108 : p(p), fac(computeFactorialsMod(size, p)) {}
109
116 int64_t ncr(const int64_t& n, const int64_t& r) const {
117 // Base cases
118 if (r > n) {
119 return 0;
120 }
121 if (r == 1) {
122 return n % p;
123 }
124 if (r == 0 || r == n) {
125 return 1;
126 }
127 // fac is a global array with fac[r] = (r! % p)
128 const auto denominator = (fac[r] * fac[n - r]) % p;
129 const auto denominator_inv = utils::modInverse(denominator, p);
130 if (denominator_inv < 0) { // modular inverse doesn't exist
131 return -1;
132 }
133 return (fac[n] * denominator_inv) % p;
134 }
135};
136} // namespace ncr_modulo_p
137} // namespace math
138
142static void tests() {
143 struct TestCase {
144 const int64_t size;
145 const int64_t p;
146 const int64_t n;
147 const int64_t r;
148 const int64_t expected;
149
150 TestCase(const int64_t size, const int64_t p, const int64_t n,
151 const int64_t r, const int64_t expected)
152 : size(size), p(p), n(n), r(r), expected(expected) {}
153 };
154 const std::vector<TestCase> test_cases = {
155 TestCase(60000, 1000000007, 52323, 26161, 224944353),
156 TestCase(20, 5, 6, 2, 30 % 5),
157 TestCase(100, 29, 7, 3, 35 % 29),
158 TestCase(1000, 13, 10, 3, 120 % 13),
159 TestCase(20, 17, 1, 10, 0),
160 TestCase(45, 19, 23, 1, 23 % 19),
161 TestCase(45, 19, 23, 0, 1),
162 TestCase(45, 19, 23, 23, 1),
163 TestCase(20, 9, 10, 2, -1)};
164 for (const auto& tc : test_cases) {
165 assert(math::ncr_modulo_p::NCRModuloP(tc.size, tc.p).ncr(tc.n, tc.r) ==
166 tc.expected);
167 }
168
169 std::cout << "\n\nAll tests have successfully passed!\n";
170}
171
175void example() {
176 const int64_t size = 1e6 + 1;
177 const int64_t p = 1e9 + 7;
178
179 // the ncrObj contains the precomputed values of factorials modulo p for
180 // values from 0 to size
181 const auto ncrObj = math::ncr_modulo_p::NCRModuloP(size, p);
182
183 // having the ncrObj we can efficiently query the values of (n C r)%p
184 // note that time of the computation does not depend on size
185 for (int i = 0; i <= 7; i++) {
186 std::cout << 6 << "C" << i << " mod " << p << " = " << ncrObj.ncr(6, i)
187 << "\n";
188 }
189}
190
191int main() {
192 tests();
193 example();
194 return 0;
195}
Class which contains all methods required for calculating nCr mod p.
int64_t ncr(const int64_t &n, const int64_t &r) const
computes nCr % p
const std::vector< int64_t > fac
the p from (nCr % p)
NCRModuloP(const int64_t &size, const int64_t &p)
constructs an NCRModuloP object allowing to compute (nCr)p for inputs from 0 to size
static std::vector< int64_t > computeFactorialsMod(const int64_t &max_arg_val, const int64_t &mod)
stores precomputed factorial(i) % p value
int gcd(int num1, int num2)
int main()
Main function.
for assert
Functions for nCr modulo p implementation.
this namespace contains the definitions of the functions called from the class math::ncr_modulo_p::NC...
static void tests()
tests math::ncr_modulo_p::NCRModuloP
int64_t modInverse(const int64_t &a, const int64_t &m)
int64_t gcdExtended(const int64_t &a, const int64_t &b, int64_t &x, int64_t &y)
finds the values x and y such that a*x + b*y = gcd(a,b)
void example()
example showing the usage of the math::ncr_modulo_p::NCRModuloP class
represents single example inputs and expected output of the function longest_common_string_length