c++ - nCk modulo p when n % p or k % p == 0 -


i'm trying solve coding challenge on hacker rank requires 1 calculate binomial coefficients mod prime, i.e.

nchoosek(n, k, p)  

i'm using code answer works first 3 sets of inputs begins failing on 4th. stepped through in debugger , determined issue arises when:

n % p == 0 || k % p == 0 

i need know how modify current solution handle specific cases n % p == 0 or k % p == 0. none of answers i've found on stack exchange seem address specific case. here's code:

#include <iostream> #include <fstream>  long long factorialexponent(long long n, long long p) {     long long ex = 0;         {         n /= p;         ex += n;     }while(n > 0);     return ex; }  unsigned long long modularmultiply(unsigned long long a, unsigned long long b, unsigned long p) {   unsigned long long a1 = (a >> 21), a2 = & ((1ull << 21) - 1);   unsigned long long temp = (a1 * b) % p;   // doesn't overflow under assumptions   temp = (temp << 21) % p;                  // neither   temp += (a2 * b) % p;                       // nor   return temp % p; }  unsigned long long modularinverse(unsigned long long k, unsigned long m) {     if (m == 0) return (k == 1 || k == -1) ? k : 0;     if (m < 0) m = -m;     k %= m;     if (k < 0) k += m;     int neg = 1;     unsigned long long p1 = 1, p2 = 0, k1 = k, m1 = m, q, r, temp;     while(k1 > 0) {       q = m1 / k1;       r = m1 % k1;       temp = q*p1 + p2;       p2 = p1;       p1 = temp;       m1 = k1;       k1 = r;       neg = !neg;     }     return neg ? m - p2 : p2; }  // preconditions: 0 <= k <= min(n,p-1); p > 1 prime unsigned long long choosemodtwo(unsigned long long n, unsigned long long k, unsigned long p) {     // reduce n modulo p     n %= p;      // trivial checks     if (n < k) {          return 0;     }      if (k == 0 || k == n) {         return 1;     }      // 0 < k < n, save bit of work if k > n/2     if (k > n/2) {         k = n-k;     }     // calculate numerator , denominator modulo p     unsigned long long num = n, den = 1;     for(n = n-1; k > 1; --n, --k)     {         num = modularmultiply(num, n, p);         den = modularmultiply(den, k, p);     }      den = modularinverse(den,p);     return modularmultiply(num, den, p); }  // preconditions: 0 <= k <= n; p > 1 prime long long choosemodone(long long n, long long k, const unsigned long p) {     // small k, no recursion necessary     if (k < p) return choosemodtwo(n,k,p);     unsigned long long q_n, r_n, q_k, r_k, choose;     q_n = n / p;     r_n = n % p;     q_k = k / p;     r_k = k % p;      choose = choosemodtwo(r_n, r_k, p);     // if exponent of p in choose(n,k) isn't determined 0     // before calculation gets serious, short-cut here:     // if (choose == 0) return 0;     return modularmultiply(choose, choosemodone(q_n, q_k, p), p);  }  unsigned long long modularbinomialcoefficient(unsigned long long n, unsigned long long k, const unsigned long p) {     // deal trivial cases first     if (k < 0 || n < k) return 0;     if (k == 0 || k == n) return 1;     // check whether choose(n,k) divisible p     if (factorialexponent(n, p) > factorialexponent(k, p) + factorialexponent(n - k, p)) return 0;     // if it's not divisible, generic work     return choosemodone(n, k, p); }  int main() {    //std::ifstream fin ("input03.txt");   std::ifstream fin ("test.in");    int kmod = 1000003;   int t;   fin >> t;   int n = t;   //std::cin >> t;    unsigned long long n, k;   unsigned long long a, b;   int result[n];   int index = 0;    while (t--) {      fin >> n >> k;      = modularbinomialcoefficient(n - 3, k, kmod);     b = modularbinomialcoefficient(n + k, n - 1, kmod);      // (1 / (n + k) * nck(n - 3, k) * nck(n + k, n - 1)) % 1000003     unsigned long long x = modularmultiply(a, b, kmod);     unsigned long long y = modularmultiply(x, modularinverse((n + k), kmod), kmod);      result[index] = y;     index++;   }    for(int = 0; < n; i++) {     std::cout << result[i] << "\n";   }    return 0; }  input: 6 90 13 65434244 16341234 23424244 12341234 424175 341198 7452123  23472 56000168 16000048  output: 815483 715724 92308 903465 241972 0 <-- incorrect, should be: 803478 

constraints:
4 <= n <= 10^9
1 <= k <= n

you can use lucas' theorem reduce problem ceil(log_p(n)) subproblems k, n < p: write n = n_m * p^m + ... + n_0 , k = k_m * p^m + ... + k_0 in base p (n_i, k_i < p digits), have

c(n,k) = prod(i = 0 m, c(n_i, k_i))  (mod p) 

the subproblems easy solve, because every factor of k! has inverse modulo p. algorithm runtime complexity o(p log(n)), better of ivaylo's code in case of p << n, if understand correctly.

int powmod(int x, int e, int p) {     if (e == 0) return 1;     if (e & 1) return (long long)x * powmod(x, e - 1, p) % p;     long long rt = powmod(x, e / 2, p);     return rt * rt % p; }  int binom_coeff_mod_prime(int n, int k, int p) {     long long res = 1;     while (n || k) {         int n = n % p, k = k % p;         (int = n - k + 1; <= n; ++i)             res = res * % p;         (int = 1; <= k; ++i)             res = res * powmod(i, p - 2, p) % p;         n /= p;         k /= p;     }     return res; } 

Comments

Popular posts from this blog

c++ - OpenCV Error: Assertion failed <scn == 3 ::scn == 4> in unknown function, -

php - render data via PDO::FETCH_FUNC vs loop -

The canvas has been tainted by cross-origin data in chrome only -