📜  计算nCr%p |第三套(使用费马小定理)

📅  最后修改于: 2021-05-04 16:03:28             🧑  作者: Mango

给定三个数字n,r和p,计算n C r mod p的值。这里p是大于n的质数。在此, n C r是二项式系数。
例子:

Input:  n = 10, r = 2, p = 13
Output: 6
Explanation: 10C2 is 45 and 45 % 13 is 6.

Input:  n = 6, r = 2, p = 13
Output: 2

在之前的文章中,我们讨论了以下方法。
计算n C r %p |设置1(简介和动态编程解决方案)
计算n C r %p |第二套(卢卡斯定理)
在这篇文章中,讨论了基于费马定理的解决方案。
背景:
费马小定理和模逆
费马小定理指出,如果p是素数,那么对于任何整数a,数字a p – ap的整数倍。在模块化算术的表示法中,这表示为:
a p = a(模p)
例如,如果a = 2且p = 7,则2 7 = 128,而128 – 2 = 7×18是7的整数倍。
如果a不能被p整除,则Fermat的小定理等于a – 1 – 1是p的整数倍,即
一个p-1 = 1(mod p)
如果我们将双方都乘以-1 ,我们得到。
a p-2 = a -1 (mod p)
因此我们可以找到p-2的模逆。
计算方式:

We know the formula for  nCr 
nCr = fact(n) / (fact(r) x fact(n-r)) 
Here fact() means factorial.

 nCr % p = (fac[n]* modIverse(fac[r]) % p *
               modIverse(fac[n-r]) % p) % p;
Here modIverse() means modular inverse under
modulo p.

以下是上述算法的实现。在以下实现中,数组fac []用于存储所有计算出的阶乘值。

C++
// A modular inverse based solution to
// compute nCr % p
#include 
using namespace std;
 
/* Iterative Function to calculate (x^y)%p
in O(log y) */
unsigned long long power(unsigned long long x,
                                  int y, int p)
{
    unsigned long long res = 1; // Initialize result
 
    x = x % p; // Update x if it is more than or
    // equal to p
 
    while (y > 0)
    {
     
        // If y is odd, multiply x with result
        if (y & 1)
            res = (res * x) % p;
 
        // y must be even now
        y = y >> 1; // y = y/2
        x = (x * x) % p;
    }
    return res;
}
 
// Returns n^(-1) mod p
unsigned long long modInverse(unsigned long long n, 
                                            int p)
{
    return power(n, p - 2, p);
}
 
// Returns nCr % p using Fermat's little
// theorem.
unsigned long long nCrModPFermat(unsigned long long n,
                                 int r, int p)
{
    // If n


Java
// A modular inverse based solution to
// compute nCr %
import java.io.*;
 
class GFG {
 
    /* Iterative Function to calculate
    (x^y)%p in O(log y) */
    static int power(int x, int y, int p)
    {
 
        // Initialize result
        int res = 1;
 
        // Update x if it is more than or
        // equal to p
        x = x % p;
 
        while (y > 0) {
 
            // If y is odd, multiply x
            // with result
            if (y % 2 == 1)
                res = (res * x) % p;
 
            // y must be even now
            y = y >> 1; // y = y/2
            x = (x * x) % p;
        }
 
        return res;
    }
 
    // Returns n^(-1) mod p
    static int modInverse(int n, int p)
    {
        return power(n, p - 2, p);
    }
 
    // Returns nCr % p using Fermat's
    // little theorem.
    static int nCrModPFermat(int n, int r,
                             int p)
    {
 
          if (n


Python3
# Python3 function to
# calculate nCr % p
def ncr(n, r, p):
    # initialize numerator
    # and denominator
    num = den = 1
    for i in range(r):
        num = (num * (n - i)) % p
        den = (den * (i + 1)) % p
    return (num * pow(den,
            p - 2, p)) % p
 
# p must be a prime
# greater than n
n, r, p = 10, 11, 13
print("Value of nCr % p is",
               ncr(n, r, p))


C#
// A modular inverse based solution to
// compute nCr % p
using System;
 
class GFG {
 
    /* Iterative Function to calculate
    (x^y)%p in O(log y) */
    static int power(int x, int y, int p)
    {
 
        // Initialize result
        int res = 1;
 
        // Update x if it is more than or
        // equal to p
        x = x % p;
 
        while (y > 0) {
 
            // If y is odd, multiply x
            // with result
            if (y % 2 == 1)
                res = (res * x) % p;
 
            // y must be even now
            y = y >> 1; // y = y/2
            x = (x * x) % p;
        }
 
        return res;
    }
 
    // Returns n^(-1) mod p
    static int modInverse(int n, int p)
    {
        return power(n, p - 2, p);
    }
 
    // Returns nCr % p using Fermat's
    // little theorem.
    static int nCrModPFermat(int n, int r,
                             int p)
    {
 
      if (n


PHP
 0)
    {
         
        // If y is odd,
        // multiply x
        // with result
        if ($y & 1)
            $res = ($res * $x) % $p;
 
        // y must be
        // even now
        // y = y/2
        $y = $y >> 1;
        $x = ($x * $x) % $p;
    }
    return $res;
}
 
// Returns n^(-1) mod p
function modInverse($n, $p)
{
    return power($n, $p - 2, $p);
}
 
// Returns nCr % p using
// Fermat's little
// theorem.
function nCrModPFermat($n, $r, $p)
{
     
    if ($n<$r)
          return 0;
      // Base case
    if ($r==0)
        return 1;
 
    // Fill factorial array so that we
    // can find all factorial of r, n
    // and n-r
    //$fac[$n+1];
    $fac[0] = 1;
    for ($i = 1; $i <= $n; $i++)
        $fac[$i] = $fac[$i - 1] *
                        $i % $p;
 
    return ($fac[$n] * modInverse($fac[$r], $p) % $p *
             modInverse($fac[$n - $r], $p) % $p) % $p;
}
 
    // Driver Code
    // p must be a prime
    // greater than n.
    $n = 10;
    $r = 2;
    $p = 13;
    echo "Value of nCr % p is ",
         nCrModPFermat($n, $r, $p);
         
// This code is contributed by Ajit.
?>


输出:
Value of nCr % p is 6