Given three numbers n, r and p, the task is to compute the value of nCr % p.
Note: p is a square-free number and the largest prime factor of p ≤ 50.
Examples:
Input: n = 10, r = 2, p = 13 Output: 6 Explanation: 10C2 is 45 and 45 % 13= 6
Input: n = 6, r = 2, p = 13 Output: 2
Approach: We have already discussed several other approaches of this problem. Following is the list of the approaches:
Here we will be discussing another approach using the concept of Lucas Theorem and the Chinese Remainder Theorem. So if you are unaware of those two theorems, go through them by following the links given here.
To solve the problem follow the steps as mentioned here.
- First, find all the prime factors of p.
- Create a vector to store the nCr % m for every prime(m) in prime factors of p using the Lucas Theorem.
- Now, using Chinese remainder theorem, calculate min_x such that min_x % primes[i] = rem[i].
Below is the implementation of the above approach:
C++
#include <bits/stdc++.h>
using namespace std;
#define ll long long
class Solution {
public :
int nCrModM( int n, int r, int p)
{
vector< int > primes = findPrimeFactors(p);
vector< int > rem;
for ( auto m : primes)
rem.push_back(Lucas(n, r, m));
int min_x = 0;
while ( true ) {
bool found = true ;
for ( int i = 0; i < primes.size();
i++) {
if (min_x % primes[i] != rem[i]) {
found = false ;
break ;
}
}
if (found) {
return min_x;
}
min_x++;
}
return min_x;
}
int Lucas( int n, int r, int m)
{
if (r == 0)
return 1;
int ni = n % m;
int ri = r % m;
return (pascal(ni, ri, m)
* Lucas(n / m, r / m, m))
% m;
}
ll pascal( int n, int r, int m)
{
if (r == 0 or r == n)
return 1;
int nCr[r + 1];
memset (nCr, 0, sizeof (nCr));
nCr[0] = 1;
for ( int i = 1; i <= n; i++) {
for ( int j = min(r, i); j > 0; j--)
nCr[j]
= (nCr[j] + nCr[j - 1]) % m;
}
return nCr[r];
}
vector< int > findPrimeFactors( int n)
{
vector< int > primes;
if (n % 2 == 0) {
primes.push_back(2);
while (n % 2 == 0)
n >>= 1;
}
for ( int i = 3; n > 1; i += 2) {
if (n % i == 0) {
primes.push_back(i);
while (n % i == 0)
n /= i;
}
}
return primes;
}
};
int main()
{
int n = 10, r = 2, p = 13;
Solution obj;
int ans = obj.nCrModM(n, r, p);
cout << ans;
return 0;
}
|
Java
import java.util.*;
class GFG{
public int nCrModM( int n, int r, int p)
{
Vector<Integer> primes = findPrimeFactors(p);
Vector<Integer> rem = new Vector<Integer>();
for ( int m : primes)
rem.add(Lucas(n, r, m));
int min_x = 0 ;
while ( true ) {
boolean found = true ;
for ( int i = 0 ; i < primes.size();
i++) {
if (min_x % primes.get(i) != rem.get(i)) {
found = false ;
break ;
}
}
if (found) {
return min_x;
}
min_x++;
}
}
int Lucas( int n, int r, int m)
{
if (r == 0 )
return 1 ;
int ni = n % m;
int ri = r % m;
return (pascal(ni, ri, m)
* Lucas(n / m, r / m, m))
% m;
}
public int pascal( int n, int r, int m)
{
if (r == 0 || r == n)
return 1 ;
int []nCr = new int [r + 1 ];
nCr[ 0 ] = 1 ;
for ( int i = 1 ; i <= n; i++) {
for ( int j = Math.min(r, i); j > 0 ; j--)
nCr[j]
= (nCr[j] + nCr[j - 1 ]) % m;
}
return nCr[r];
}
Vector<Integer> findPrimeFactors( int n)
{
Vector<Integer> primes = new Vector<Integer>();
if (n % 2 == 0 ) {
primes.add( 2 );
while (n % 2 == 0 )
n >>= 1 ;
}
for ( int i = 3 ; n > 1 ; i += 2 ) {
if (n % i == 0 ) {
primes.add(i);
while (n % i == 0 )
n /= i;
}
}
return primes;
}
public static void main(String[] args)
{
int n = 10 , r = 2 , p = 13 ;
GFG obj = new GFG();
int ans = obj.nCrModM(n, r, p);
System.out.print(ans);
}
}
|
Python3
class Solution:
def nCrModM( self , n, r, p):
primes = self .findPrimeFactors(p)
rem = []
for m in primes:
rem.append( self .Lucas(n, r, m))
min_x = 0
while ( True ):
found = True
for i in range ( 0 , len (primes)):
if (min_x % primes[i] ! = rem[i]):
found = False
break
if (found):
return min_x
min_x + = 1
return min_x
def Lucas( self , n, r, m):
if (r = = 0 ):
return 1
ni = n % m
ri = r % m
return ( self .pascal(ni, ri, m) * self .Lucas(n / / m, r / / m, m)) % m
def pascal( self , n, r, m):
if (r = = 0 or r = = n):
return 1
nCr = [ 0 for _ in range (r + 1 )]
nCr[ 0 ] = 1
for i in range ( 1 , n + 1 ):
for j in range ( min (r, i), 0 , - 1 ):
nCr[j] = (nCr[j] + nCr[j - 1 ]) % m
return nCr[r]
def findPrimeFactors( self , n):
primes = []
if (n % 2 = = 0 ):
primes.append( 2 )
while (n % 2 = = 0 ):
n >> = 1
i = 3
while (n > 1 ):
if n % i = = 0 :
primes.append(i)
while (n % i = = 0 ):
n / / = i
i + = 2
return primes
if __name__ = = "__main__" :
n = 10
r = 2
p = 13
obj = Solution()
ans = obj.nCrModM(n, r, p)
print (ans)
|
C#
using System;
using System.Collections.Generic;
class GFG {
public int nCrModM( int n, int r, int p)
{
List< int > primes = findPrimeFactors(p);
List< int > rem = new List< int >();
foreach ( var m in primes) rem.Add(Lucas(n, r, m));
int min_x = 0;
while ( true ) {
bool found = true ;
for ( int i = 0; i < primes.Count; i++) {
if (min_x % primes[i] != rem[i]) {
found = false ;
break ;
}
}
if (found) {
return min_x;
}
min_x++;
}
}
int Lucas( int n, int r, int m)
{
if (r == 0)
return 1;
int ni = n % m;
int ri = r % m;
return (pascal(ni, ri, m) * Lucas(n / m, r / m, m))
% m;
}
public int pascal( int n, int r, int m)
{
if (r == 0 || r == n)
return 1;
int [] nCr = new int [r + 1];
nCr[0] = 1;
for ( int i = 1; i <= n; i++) {
for ( int j = Math.Min(r, i); j > 0; j--)
nCr[j] = (nCr[j] + nCr[j - 1]) % m;
}
return nCr[r];
}
List< int > findPrimeFactors( int n)
{
List< int > primes = new List< int >();
if (n % 2 == 0) {
primes.Add(2);
while (n % 2 == 0)
n >>= 1;
}
for ( int i = 3; n > 1; i += 2) {
if (n % i == 0) {
primes.Add(i);
while (n % i == 0)
n /= i;
}
}
return primes;
}
public static void Main( string [] args)
{
int n = 10, r = 2, p = 13;
GFG obj = new GFG();
int ans = obj.nCrModM(n, r, p);
Console.WriteLine(ans);
}
}
|
Javascript
function nCrModM(n, r, p) {
primes = findPrimeFactors(p);
rem = [];
for (let i = 0; i < primes.length; i++) {
let m = primes[i];
rem.push(Lucas(n, r, m));
}
let min_x = 0;
while ( true ) {
let found = true ;
for (let i = 0; i < primes.length; i++) {
if (min_x % primes[i] != rem[i]) {
found = false ;
break ;
}
}
if (found) {
return min_x;
}
min_x++;
}
return min_x;
}
function Lucas(n, r, m) {
if (r == 0 || r == n)
return 1;
let ni = n % m;
let ri = r % m;
return (pascal(ni, ri, m) * Lucas(Math.floor(n / m), Math.floor(r / m), m)) % m;
}
function pascal(n, r, m) {
if (r == 0 || r == n)
return 1;
let nCr = []
for (let i = 0; i < r + 1; i++) {
nCr.push(0);
}
nCr[0] = 1;
for (let i = 1; i <= n; i++) {
for (let j = Math.min(r, i); j > 0; j--)
nCr[j] = (nCr[j] + nCr[j - 1]) % m;
}
return nCr[r];
}
function findPrimeFactors(n) {
let primes = [];
if (n % 2 == 0) {
primes.push(2);
while (n % 2 == 0)
n >>= 1;
}
for (let i = 3; n > 1; i += 2) {
if (n % i == 0) {
primes.push(i);
while (n % i == 0)
n /= i;
}
}
return primes;
}
let n = 10;
let r = 2;
let p = 13;
let ans = nCrModM(n, r, p);
console.log(ans);
|
Time Complexity: O(p + log(p * n)) Auxiliary Space: O(p)
|