Using Log-Factorial

Log-Factorial
Log-Factorial is one of the best ways of computing nPr, nCr, and occasionally even n! itself.

Math:

log (n!) = log(n) + log(n-1) + log(n-2) .. + log(1)

exp(log(n!)) = n!

From these two facts, it is easy to generate an array of log (n!):

Java
double[] arr = new double[10001] ; arr[0] = 0 ; // since exp(0) = 1, and 0! = 1, this is a suitable base case for (int i = 0 ; i &lt;= 10000 ; i ++) arr[i] = arr[i-1] + Math.log(i) ;

On its own, this isn't terribly useful (n! remains to be large) - but what if we want to compute, say, n C r?

n C r = n! /[ (n-k)! * k!]

log (nCr) = log(n!) - log((n-k)!) - log(k!)

Java
// Using the above code to generate an array: Scanner input = new Scanner(System.in) ; int N = input.nextInt ; int K = input.nextInt ; double ans = arr[N] - arr[N-K] - arr[K] ; ans = Math.exp(ans) ; ans = Math.floor(ans + .5) ;

Now, ignoring startup time, we have an algorithm to compute n C r in O(1) time.

For extra precision, you can make the array out of BigDecimals. Note that BigDecimal doesn't have a log function, so you use doubles for the logarithm - just store the final result with BigDecimal to reduce round-off errors:

Java
BigDecimal[] newArr = new BigDecimal[10001] ; newArr[0] = new BigDecimal("0") ; for (int i = 0 ; i &lt;= 10000 ; i ++) {    double a = Math.log(i) ; newArr[i] = newArr[i-1].add(new BigDecimal(a)) ; } Alternatively, you could write your own logarithm function for BigDecimal - I'd expect that it'd take O(log n) time, though, so it'd be a performance slowdown.

This array and algorithm is generalizable to several types of problems where you need to compute nCr, nPr, etc.

UVA Problems:
10375 Choose and Divide (Need BigDecimal implementation in Java, long double in C++)