I am trying to come up with an efficient way to list all divisors of a big factorial. Let's say 1000!. It is quite impossible with brute force. Is there an efficient approach?
I need to process them i.e. to find their sum for a programming challenge.
Find the prime factorisation of each number <= 1000. I would store this as a dictionary of prime -> power. E.g. for a single number like 24 {2: 3, 3: 1} because 24 is 2**3 * 3**1.
Find the prime factorisation of 1000!. This is the combination of the dictionaries of numbers <= 1000 combined by summing all the values for each of the keys (the primes).
You can then use equation 14 on this page as #AakashM already said.
Following are the steps for an efficient solution:
n! can be represented as :- n! = (a1^p1) (a2^p2)x...(ak^pk).
where ak is the prime divisor lesser than n and pk is the highest power
which can divide n!.
Through sieve find the prime number and the highest power can be
easily find out by :
countofpower = [n/a] + [n/a^2] + [n/a^3] +...... or ` while (n)
{
n/ = a;
ans += n
}
Count Of Factors = (ans1 +1)*(ans2 +1)*....(ansk +1)
After calculating this last step is the sum :
SUM = product of all (pow(ak,pk+1)-1)/(ak-1);
ex = 4!
4! = 2^3 * 3^1;
count of factors = (3+1)*(1+1) = 8 (1,2,3,4,6,8,12,24)
sum = ( 1 + 2 + 4 + 8)*(1 + 3) = 60.
Related
Problem : 5 monkeys, 5 snakes and 5 tigers are standing in a line in a grocery store, with animals of the same species being indistinguishable. A monkey stands in the front of the line, and a tiger stands at the end of the line. Unfortunately, tigers and monkeys are sworn enemies, so monkeys and tigers cannot stand in adjacent places in line. Compute the number of possible arrangements of the line.
Solving this problem by hand is daunting. I want to write a program to output the possible arrangements and also count the total arrangements. My first thought was to use a brute force. Monkeys, snakes, and tigers can be represented by the letters M, S, and T respectively. With 1 M at start of string and 1 T at the end, there are 13!/(4!4!5!) = 90,090 possibilities. I would then remove arrangements that do not satisfy the second condition about adjacency.
My second thought was to first compute the number of arrangements where M and T are adjacent and then subtract this number from 90,090. I am new to programming so I am not sure how to do this.
Is there a better way to approach these types of problems? Any hints?
Thank you.
TL;DR: python solution using sympy
import sympy # sympy.ntheory.multinomial_coefficients
import math # math.comb
def count_monkeytigers(n_monkeys, n_snakes, n_tigers):
return sum(
m * math.comb(n_monkeys - 1, mb_minus1) * math.comb(n_tigers - 1, tb_minus1)
for (mb_minus1, eb, tb_minus1), m in
sympy.ntheory.multinomial_coefficients(3, n_snakes-1).items()
)
Explanation
We already know that there is an M at the beginning, a T at the end, and five S in the string:
M?? S ?? S ?? S ?? S ?? S ??T
Since M and T cannot be adjacent, and the only way to separate them is with an S, you can think of the S as separators; the five S are cutting the string into 6 "bins". Every bin can either be empty, or contain one or more M, or contain one or more T. Furthermore, the first bin contains at least an M, and the last bin contains at least a T.
To count all permutations of the string, we can do the following:
Loop over the triplets (monkey_bins, empty_bins, tiger_bins) deciding how many bins have monkeys, are empty, or have tigers;
For the loop, we can use bounds 1 <= monkey_bins <= 5; 0 <= empty_bins <= 5 - monkey_bins; tiger_bins = 6 - monkey_bins - empty_bins;
Count the number m of ways to choose monkey_bins bins, empty_bins bins and tiger_bins bins among 6 bins (Multinomial coefficient);
Count the number monkey_partitions of ways to place n_monkeys 'M' into monkey_bins bins with at least one M per bin (Stars and bars theorem 1);
Count the number tiger_partitions of ways to place n_tigers 'T' into tiger_bins bins with at least one T per bin (Stars and bars theorem 1;
Add m * monkey_partitions * tiger_partitions to the count.
Python code with loops
import math
def multinomial(*params):
return math.prod(math.comb(sum(params[:i]), x) for i, x in enumerate(params, 1))
def count_monkeytigers(n_monkeys, n_snakes, n_tigers):
result = 0
for monkey_bins in range(1, n_snakes + 1):
for empty_bins in range(0, n_snakes + 1 - monkey_bins):
tiger_bins = n_snakes + 1 - monkey_bins - empty_bins
m = multinomial(monkey_bins - 1, empty_bins, tiger_bins - 1) # nb permutations of the 3 types of bins
monkey_partitions = math.comb(n_monkeys - 1, monkey_bins - 1)
tiger_partitions = math.comb(n_tigers - 1, tiger_bins - 1)
result += m * monkey_partitions * tiger_partitions
return result
print(count_monkeytigers(5, 5, 5))
# 1251
print(count_monkeytigers(2,2,2))
# 3
# = len(['MMSSTT', 'MSMSTT', 'MMSTST'])
The code for multinomial comes from this question:
Does python have a function which computes multinomial coefficients?
Note that we're only using a "trinomial" coefficient here, so you can replace function multinomial with this simpler function if you want:
def trinomial(k1,k2,k3):
return math.comb(k1+k2+k3, k1) * math.comb(k2+k3, k2)
Python code using sympy
In the previous python code, we're manually looping over the possible triplets (monkey_bins, empty_bins, tiger_bins) and using the corresponding binomial coefficients. As it turns out, sympy.ntheory.multinomial_coefficients(m, n) returns a dictionary that contains specifically those triplets as keys and the corresponding multinomial coefficients as values!
We can use that to shorten our code:
import sympy # sympy.ntheory.multinomial_coefficients
import math # math.comb
def count_monkeytigers(n_monkeys, n_snakes, n_tigers):
return sum(
m * math.comb(n_monkeys - 1, mb_minus1) * math.comb(n_tigers - 1, tb_minus1)
for (mb_minus1, eb, tb_minus1), m in
sympy.ntheory.multinomial_coefficients(3, n_snakes-1).items()
)
print(count_monkeytigers(5, 5, 5))
# 1251
print(count_monkeytigers(2,2,2))
# 3
# = len(['MMSSTT', 'MSMSTT', 'MMSTST'])
Note that the dictionary multinomial_coefficients(3, n) contains all triplets of nonnegative numbers summing to n, including those where the middle-element empty_bins is equal to n, and the other two elements are 0. But we want at least one bin with monkeys, and at least one bin with tigers; hence I called the triplet (mb_minus1, eb, tb_minus1) rather than (mb, eb, tb), and accordingly I used n_snakes-1 rather than n_snakes+1 as the sum of the triplet.
Before writing code directly , Just solve the question on paper upto the factorial notations , then you can easily find factorial in Code
At first , fix 1 monkey at front and 1 tiger at end .
Then try to fix remaining tigers , then fix snakes in adjancent of tigers , Atleast one snake must be in adjacent of a tiger and then fix monkeys in adjacent of snakes
Let's assume I have an N-bit stream of generated bits. (In my case 64kilobits.)
Whats the probability of finding a sequence of X "all true" bits, contained within a stream of N bits. Where X = (2 to 16), and N = (16 to 1000000), and X < N.
For example:
If N=16 and X=5, whats the likelyhood of finding 11111 within a 16-bit number.
Like this pseudo-code:
int N = 1<<16; // (64KB)
int X = 5;
int Count = 0;
for (int i = 0; i < N; i++) {
int ThisCount = ContiguousBitsDiscovered(i, X);
Count += ThisCount;
}
return Count;
That is, if we ran an integer in a loop from 0 to 64K-1... how many times would 11111 appear within those numbers.
Extra rule: 1111110000000000 doesn't count, because it has 6 true values in a row, not 5. So:
1111110000000000 = 0x // because its 6 contiguous true bits, not 5.
1111100000000000 = 1x
0111110000000000 = 1x
0011111000000000 = 1x
1111101111100000 = 2x
I'm trying to do some work involving physically-based random-number generation, and detecting "how random" the numbers are. Thats what this is for.
...
This would be easy to solve if N were less than 32 or so, I could just "run a loop" from 0 to 4GB, then count how many contiguous bits were detected once the loop was completed. Then I could store the number and use it later.
Considering that X ranges from 2 to 16, I'd literally only need to store 15 numbers, each less than 32 bits! (if N=32)!
BUT in my case N = 65,536. So I'd need to run a loop, for 2^65,536 iterations. Basically impossible :)
No way to "experimentally calculate the values for a given X, if N = 65,536". So I need maths, basically.
Fix X and N, obiously with X < N. You have 2^N possible values of combinations of 0 and 1 in your bit number, and you have N-X +1 possible sequences of 1*X (in this part I'm only looking for 1's together) contained in you bit number. Consider for example N = 5 and X = 2, this is a possible valid bit number 01011, so fixed the last two characteres (the last two 1's) you have 2^2 possible combinations for that 1*Xsequence. Then you have two cases:
Border case: Your 1*X is in the border, then you have (2^(N -X -1))*2 possible combinations
Inner case: You have (2^(N -X -2))*(N-X-1) possible combinations.
So, the probability is (border + inner )/2^N
Examples:
1)N = 3, X =2, then the proability is 2/2^3
2) N = 4, X = 2, then the probaility is 5/16
A bit brute force, but I'd do something like this to avoid getting mired in statistics theory:
Multiply the probabilities (1 bit = 0.5, 2 bits = 0.5*0.5, etc) while looping
Keep track of each X and when you have the product of X bits, flip it and continue
Start with small example (N = 5, X=1 - 5) to make sure you get edge cases right, compare to brute force approach.
This can probably be expressed as something like Sum (Sum 0.5^x (x = 1 -> 16) (for n = 1 - 65536) , but edge cases need to be taken into account (i.e. 7 bits doesn't fit, discard probability), which gives me a bit of a headache. :-)
#Andrex answer is plain wrong as it counts some combinations several times.
For example consider the case N=3, X=1. Then the combination 101 happens only 1/2^3 times but the border calculation counts it two times: one as the sequence starting with 10 and another time as the sequence ending with 01.
His calculations gives a (1+4)/8 probability whereas there are only 4 unique sequences that have at least a single contiguous 1 (as opposed to cases such as 011):
001
010
100
101
and so the probability is 4/8.
To count the number of unique sequences you need to account for sequences that can appear multiple times. As long as X is smaller than N/2 this will happens. Not sure how you can count them tho.
For example,
n = 4 (4x1) 1 way
n = 10 (4x1, 6x1) (10x1) 2 ways
Is there any equation can express the number of way?
You have used recurrence-relation tag - yes, it is possible to use recurrence to calculate the number of ways.
P(N) = P(N-10) + P(N-6) + P(N-4)
P(0) = 1
Explanation - you can get sum N, using (N-10) cents sum and 10-cent coin and so on.
For rather large values of N recursive algorithm will work too long, so one could build dynamic programming algorithm to accelerate calculations (DP will reuse calculated values for smaller sums)
Suppose you have a list of denominations. In your case it is A = [4,6,10]. So suppose you have the following things:
A = [4,6,10]
Length of list A = N
Sum = K
The problem can be written as:
# Given the list of denominations, its length and the sum.
P(A,N,K) = 0 if N < 0 or K < 0,
1 if K = 0,
P(A,N-1,K) + P(A,N-1,k-A[N]) #A[N]-> Nth element of list
As we can see the possibility of re-using sub-problems, DP will work wonderfully.
Given the range [1, 2 Million], for each number in this range I need to generate
and store the number of the divisors of each integer in an array.
So if x=p1^(a1)*p2^a2*p3^a3, where p1, p2, p3 are primes,
the total number of divisors of x is given by (p1+1)(p2+1)(p3+1). I generated all
the primes below 2000 and for each integer in the range, I did trial division
to get the power of each prime factor and then used the formula above to calculate
the number of divisors and stored in an array.
But, doing this is quite slow and takes around 5 seconds to generate the number of divsors
for all the numbers in the given range.
Can we do this sum in some other efficient way, may be without factorizing each
of the numbers?
Below is the code that I use now.
typedef unsigned long long ull;
void countDivisors(){
ull PF_idx=0, PF=0, ans=1, N=0, power;
for(ull i=2; i<MAX; ++i){
if (i<SIEVE_SIZE and isPrime[i]) factors[i]=2;
else{
PF_idx=0;
PF=primes[PF_idx];
ans=1;
N=i;
while(N!=1 and (PF*PF<=N)){
power = 0;
while(N%PF==0){ N/=PF; ++power;}
ans*=(power+1);
PF = primes[++PF_idx];
}
if (N!=1) ans*=2;
factors[i] = ans;
}
}
}
First of all your formula is wrong. According to your formula, the sum of the divisors of 12 should be 12. In fact it is 28. The correct formula is (p1a1 - 1)*(p2a2 - 1) * ... * (pkak - 1)/( (p1 - 1) * (p2 - 1) * ... * (pk - 1) ).
That said, the easiest approach is probably just to do a sieve. One can get clever with offsets, but for simplicity just make an array of 2,000,001 integers, from 0 to 2 million. Initialize it to 0s. Then:
for (ull i = 1; i < MAX; ++i) {
for (ull j = i; j < MAX; j += i) {
factors[j] += i;
}
}
This may feel inefficient, but it is not that bad. The total work taken for the numbers up to N is N + N/2 + N/3 + ... + N/N = O(N log(N)) which is orders of magnitude less than trial division. And the operations are all addition and comparison, which are fast for integers.
If you want to proceed with your original idea and formula, you can make that more efficient by using a modified sieve of Eratosthenes to create an array from 1 to 2 million listing a prime factor of each number. Building that array is fairly fast, and you can take any number and factorize it much, much more quickly than you could with trial division.
Why does this code return the sum of factors of a number?
In several Project Euler problems, you are asked to compute the sum of factors as a part of the problem. On one of the forums there, someone posted the following Java code as the best way of finding that sum, since you don't actually have to find the individual factors, just the prime ones (you don't need to know Java, you can skip to my summary below):
public int sumOfDivisors(int n)
{
int prod=1;
for(int k=2;k*k<=n;k++){
int p=1;
while(n%k==0){
p=p*k+1;
n/=k;
}
prod*=p;
}
if(n>1)
prod*=1+n;
return prod;
}
Now, I've tried it many times and I see that it works. The question is, why?
Say you factor 100: 1,2,4,5,10,20,25,50,100. The sum is 217. The prime factorization is 2*2*5*5. This function gives you [5*(5+1)+1]*[2*(2+1)+1] = [25+5+1]*[4+2+1] = 217
Factoring 8: 1,2,4,8. The sum is 15. The prime factorization is 2*2*2. This function gives you [2*(2*(2+1)+1)+1]=15
The algorithm boils down to (using Fi to mean the ith index of the factor F or F sub i):
return product(sum(Fi^k, k from 0 to Ni), i from 1 to m)
where m is number of unique prime factors, Ni is the number of times each unique factor occurs in the prime factorization.
Why is this formula equal to the sum of the factors? My guess is that it equals the sum of every unique combination of prime factors (i.e. every unique factor) via the distributive property, but I don't see how.
Let's look at the simplest case: when n is a power of a prime number.
The factors of k^m are 1, k, k^2, k^3 ... k^m-1.
Now let's look at the inner loop of the algorithm:
After the first iteration, we have k + 1.
After the second iteration, we have k(k+1) + 1, or k^2 + k + 1
After the third iteration, we have k^3 + k^2 + k + 1
And so on...
That's how it works for numbers that are powers of a single prime. I might sit down and generalize this to all numbers, but you might want to give it a go yourself first.
EDIT: Now that this is the accepted answer, I'll elaborate a bit more by showing how the algorithm works on numbers with two distinct prime factors. It is then straightforward to generalize that to numbers with an arbitrary amount of distinct prime factors.
The factors of x^i.y^j are x^0.y^0, x^0.y^1 ... x^0.y^j, x^1.y^0...
The inner loops for each distinct prime factor generate x^i + x^i-1 + ... + x^0 (and similarly for y). Then we just multiply them together and we have our sum of factors.
The algorithm is essentially looking at the set of all ordered subsets of the prime factors of n, which is analogous to the set of factors of n.