给定三个数字n,r和p,计算n C r mod p的值。
例子:
Input: n = 10, r = 2, p = 13
Output: 6
Explanation: 10C2 is 45 and 45 % 13 is 6.
Input: n = 1000, r = 900, p = 13
Output: 8
我们强烈建议您参考下面的帖子,以此作为前提条件。
计算n C r %p |设置1(简介和动态编程解决方案)
我们在上面的集合1中引入了溢出问题并讨论了基于动态编程的解决方案。基于DP的解决方案的时间复杂度为O(n * r),并且需要O(n)空间。对于较大的n值,尤其是接近10 9的值,花费的时间和额外空间变得非常高。
在这篇文章中,讨论了基于卢卡斯定理的解决方案。该解决方案的时间复杂度为O(p 2 * Log p n),并且仅需要O(p)空间。
卢卡斯定理:
对于非负整数n和r以及质数p,以下同余关系成立:
在哪里
和
对n C r %p使用卢卡斯定理:
卢卡斯定理基本上表明,可以通过将n i C ri的结果相乘来计算n c r的值,其中n i和r i分别是n和r的基数p表示中的单个相同位置的数字。 。
这个想法是对基数p中的各个数字n i和r i进行一个一计算n i C ri 。我们可以计算这些值,这是上一篇文章中讨论的基于DP的解决方案。由于这些数字位于基数p中,因此我们永远不需要超过O(p)的空间,并且这些单个计算的时间复杂度将受到O(p 2 )的限制。
以下是上述想法的实现
C++
// A Lucas Theorem based solution to compute nCr % p
#include
using namespace std;
// Returns nCr % p. In this Lucas Theorem based program,
// this function is only called for n < p and r < p.
int nCrModpDP(int n, int r, int p)
{
// The array C is going to store last row of
// pascal triangle at the end. And last entry
// of last row is nCr
int C[r+1];
memset(C, 0, sizeof(C));
C[0] = 1; // Top row of Pascal Triangle
// One by constructs remaining rows of Pascal
// Triangle from top to bottom
for (int i = 1; i <= n; i++)
{
// Fill entries of current row using previous
// row values
for (int j = min(i, r); j > 0; j--)
// nCj = (n-1)Cj + (n-1)C(j-1);
C[j] = (C[j] + C[j-1])%p;
}
return C[r];
}
// Lucas Theorem based function that returns nCr % p
// This function works like decimal to binary conversion
// recursive function. First we compute last digits of
// n and r in base p, then recur for remaining digits
int nCrModpLucas(int n, int r, int p)
{
// Base case
if (r==0)
return 1;
// Compute last digits of n and r in base p
int ni = n%p, ri = r%p;
// Compute result for last digits computed above, and
// for remaining digits. Multiply the two results and
// compute the result of multiplication in modulo p.
return (nCrModpLucas(n/p, r/p, p) * // Last digits of n and r
nCrModpDP(ni, ri, p)) % p; // Remaining digits
}
// Driver program
int main()
{
int n = 1000, r = 900, p = 13;
cout << "Value of nCr % p is " << nCrModpLucas(n, r, p);
return 0;
}
Java
// A Lucas Theorem based solution to compute nCr % p
class GFG{
// Returns nCr % p. In this Lucas Theorem based program,
// this function is only called for n < p and r < p.
static int nCrModpDP(int n, int r, int p)
{
// The array C is going to store last row of
// pascal triangle at the end. And last entry
// of last row is nCr
int[] C=new int[r+1];
C[0] = 1; // Top row of Pascal Triangle
// One by constructs remaining rows of Pascal
// Triangle from top to bottom
for (int i = 1; i <= n; i++)
{
// Fill entries of current row using previous
// row values
for (int j = Math.min(i, r); j > 0; j--)
// nCj = (n-1)Cj + (n-1)C(j-1);
C[j] = (C[j] + C[j-1])%p;
}
return C[r];
}
// Lucas Theorem based function that returns nCr % p
// This function works like decimal to binary conversion
// recursive function. First we compute last digits of
// n and r in base p, then recur for remaining digits
static int nCrModpLucas(int n, int r, int p)
{
// Base case
if (r==0)
return 1;
// Compute last digits of n and r in base p
int ni = n%p;
int ri = r%p;
// Compute result for last digits computed above, and
// for remaining digits. Multiply the two results and
// compute the result of multiplication in modulo p.
return (nCrModpLucas(n/p, r/p, p) * // Last digits of n and r
nCrModpDP(ni, ri, p)) % p; // Remaining digits
}
// Driver program
public static void main(String[] args)
{
int n = 1000, r = 900, p = 13;
System.out.println("Value of nCr % p is "+nCrModpLucas(n, r, p));
}
}
// This code is contributed by mits
Python3
# A Lucas Theorem based solution
# to compute nCr % p
# Returns nCr % p. In this Lucas
# Theorem based program, this
# function is only called for
# n < p and r < p.
def nCrModpDP(n, r, p):
# The array C is going to store
# last row of pascal triangle
# at the end. And last entry
# of last row is nCr
C = [0] * (n + 1);
# Top row of Pascal Triangle
C[0] = 1;
# One by constructs remaining
# rows of Pascal Triangle from
# top to bottom
for i in range(1, (n + 1)):
# Fill entries of current
# row using previous row
# values
j = min(i, r);
while(j > 0):
C[j] = (C[j] + C[j - 1]) % p;
j -= 1;
return C[r];
# Lucas Theorem based function that
# returns nCr % p. This function
# works like decimal to binary
# conversion recursive function.
# First we compute last digits of
# n and r in base p, then recur
# for remaining digits
def nCrModpLucas(n, r, p):
# Base case
if (r == 0):
return 1;
# Compute last digits of n
# and r in base p
ni = int(n % p);
ri = int(r % p);
# Compute result for last digits
# computed above, and for remaining
# digits. Multiply the two results
# and compute the result of
# multiplication in modulo p.
# Last digits of n and r
return (nCrModpLucas(int(n / p), int(r / p), p) *
nCrModpDP(ni, ri, p)) % p; # Remaining digits
# Driver Code
n = 1000;
r = 900;
p = 13;
print("Value of nCr % p is",
nCrModpLucas(n, r, p));
# This code is contributed by mits
C#
// A Lucas Theorem based solution
// to compute nCr % p
using System;
class GFG
{
// Returns nCr % p. In this Lucas
// Theorem based program, this
// function is only called for
// n < p and r < p.
static int nCrModpDP(int n, int r, int p)
{
// The array C is going to store
// last row of pascal triangle
// at the end. And last entry
// of last row is nCr
int[] C = new int[r + 1];
C[0] = 1; // Top row of Pascal Triangle
// One by constructs remaining
// rows of Pascal Triangle
// from top to bottom
for (int i = 1; i <= n; i++)
{
// Fill entries of current row
// using previous row values
for (int j = Math.Min(i, r); j > 0; j--)
// nCj = (n-1)Cj + (n-1)C(j-1);
C[j] = (C[j] + C[j - 1]) % p;
}
return C[r];
}
// Lucas Theorem based function that
// returns nCr % p. This function works
// like decimal to binary conversion
// recursive function. First we compute
// last digits of n and r in base p,
// then recur for remaining digits
static int nCrModpLucas(int n, int r, int p)
{
// Base case
if (r == 0)
return 1;
// Compute last digits of n
// and r in base p
int ni = n % p;
int ri = r % p;
// Compute result for last digits
// computed above, and for remaining
// digits. Multiply the two results
// and compute the result of
// multiplication in modulo p.
return (nCrModpLucas(n / p, r / p, p) * // Last digits of n and r
nCrModpDP(ni, ri, p)) % p; // Remaining digits
}
// Driver Code
public static void Main()
{
int n = 1000, r = 900, p = 13;
Console.Write("Value of nCr % p is " +
nCrModpLucas(n, r, p));
}
}
// This code is contributed
// by ChitraNayal
PHP
0; $j--)
$C[$j] = ($C[$j] +
$C[$j - 1]) % $p;
}
return $C[$r];
}
// Lucas Theorem based function
// that returns nCr % p. This
// function works like decimal
// to binary conversion recursive
// function. First we compute last
// digits of n and r in base p,
// then recur for remaining digits
function nCrModpLucas($n, $r, $p)
{
// Base case
if ($r == 0)
return 1;
// Compute last digits
// of n and r in base p
$ni = $n % $p;
$ri = $r % $p;
// Compute result for last
// digits computed above,
// and for remaining digits.
// Multiply the two results
// and compute the result of
// multiplication in modulo p.
return (nCrModpLucas($n / $p,
$r / $p, $p) * // Last digits of n and r
nCrModpDP($ni, $ri, $p)) % $p; // Remaining digits
}
// Driver Code
$n = 1000; $r = 900; $p = 13;
echo "Value of nCr % p is " ,
nCrModpLucas($n, $r, $p);
// This code is contributed by ajit
?>
Javascript
输出:
Value of nCr % p is 8