|
| 1 | +package com.williamfiset.algorithms.math; |
| 2 | + |
| 3 | +import java.math.BigInteger; |
| 4 | + |
| 5 | +public class NChooseRModPrime { |
| 6 | + /** |
| 7 | + * Calculate the value of C(N, R) % P using Fermat's Little Theorem. |
| 8 | + * |
| 9 | + * @param N |
| 10 | + * @param R |
| 11 | + * @param P |
| 12 | + * @return The value of N choose R Modulus P |
| 13 | + */ |
| 14 | + public static long compute(int N, int R, int P) { |
| 15 | + if (R == 0) return 1; |
| 16 | + |
| 17 | + long[] factorial = new long[N + 1]; |
| 18 | + factorial[0] = 1; |
| 19 | + |
| 20 | + for (int i = 1; i <= N; i++) { |
| 21 | + factorial[i] = factorial[i - 1] * i % P; |
| 22 | + } |
| 23 | + |
| 24 | + return (factorial[N] |
| 25 | + * ModularInverse.modInv(factorial[R], P) |
| 26 | + % P |
| 27 | + * ModularInverse.modInv(factorial[N - R], P) |
| 28 | + % P) |
| 29 | + % P; |
| 30 | + } |
| 31 | + |
| 32 | + private static String bigIntegerNChooseRModP(int N, int R, int P) { |
| 33 | + if (R == 0) return "1"; |
| 34 | + BigInteger num = new BigInteger("1"); |
| 35 | + BigInteger den = new BigInteger("1"); |
| 36 | + while (R > 0) { |
| 37 | + num = num.multiply(new BigInteger("" + N)); |
| 38 | + den = den.multiply(new BigInteger("" + R)); |
| 39 | + BigInteger gcd = num.gcd(den); |
| 40 | + num = num.divide(gcd); |
| 41 | + den = den.divide(gcd); |
| 42 | + N--; |
| 43 | + R--; |
| 44 | + } |
| 45 | + num = num.divide(den); |
| 46 | + num = num.mod(new BigInteger("" + P)); |
| 47 | + return num.toString(); |
| 48 | + } |
| 49 | + |
| 50 | + public static void main(String args[]) { |
| 51 | + int N = 500; |
| 52 | + int R = 250; |
| 53 | + int P = 1000000007; |
| 54 | + int expected = Integer.parseInt(bigIntegerNChooseRModP(N, R, P)); |
| 55 | + long actual = compute(N, R, P); |
| 56 | + System.out.println(expected); // 515561345 |
| 57 | + System.out.println(actual); // 515561345 |
| 58 | + } |
| 59 | +} |
0 commit comments