Problem
Given n
and k
calculate c(n, k) % 2
.
O(n * k)
We can just use DP:
O(n)
Since we only want the answer mod 2. we just need to find how many 2
s there are in the numerator vs. denominator of n! / (k! (n-k)!)
. To do that we just need to find the number of 2
s in x!
.
O(log(n))
To improve the linear solution, let’s look at twos
function. instead of iterating over each number in n!
(1, 2, 3, …, n) let’s count how many 2
s we have, then how many 4
s we have, then 8
s and so on (until log2(n)
). This leads to a O(log(n))
solution:
O(1)
Now, can we do it faster? Let’s first print out c(n, k) % 2
and look at it:
Output:
Yes, this is the famous Sierpiński triangle fractal!
As you probably know, this simple code prints the Sierpiński triangle but upside down:
Now, changing i & j
to (i - j) & j
would flip the triangle and we get:
This perfectly matches the triangle we got from c(n, k) % 2
, which suggests the simple O(1)
solution:
Proof
Let’s take a closer look and actually prove why this simple solution works. To solve c(n, k) % 2
Let’s use Lucas’s theorem. It states that we can compute c(n, k)
by breaking down n
and k
into their digits in base p
(p
needs to be prime):
Substituting for p = 2
, each digit is either 0
or 1
. So:
c(0, 0) = c(1, 0) = c(1, 1) = 1
while,
c(0, 1) = 0
Now, based on Lucas’s theorem, in order for c(n, k) % 2
to be 1
all the terms on the right hand side need to be 1
. This means for any set bit in k
the corresponding bit in n
should be set as well. In other words:
n | k == n
or
n & k == k
or
(n - k) & k == 0