An algorithm for finding the smallest N such that N! divided by the number raised to a degree

Is there an efficient algorithm for computing the smallest integer N such that N! divided by p ^ k, where p is a relatively small prime and k is a very large integer. In other words,

factorial(N) mod p^k == 0 

If, given N and p, I would like to find how many times p divides by N !, I would use the well-known formula

 k = Sum(floor(N/p^i) for i=1,2,... 

I searched for brute force for small k values, but this approach collapses very quickly as k increases, and there seems to be no pattern that I can extrapolate to larger values.

Edited 6/13/2011

Using the suggestions suggested by Fiver and Hammar, I used quasi-bin search to solve the problem, but not quite as they expected. Using the truncated version of the second formula above, I calculated the upper bound on N as the product of k and p (using only the first term). I used 1 as the lower bound. Using the classic binary search algorithm, I calculated the midpoint between the two values ​​and calculated that k would use this average as N in the second formula, this time with all the terms used.

If the calculated k was too small, I adjusted the lower bound and repeated. Too large, I first tested to determine if k, calculated in mid-1, was less than the desired k. If so, the midpoint was returned as the nearest N. Otherwise, I adjusted the top point and repeated.

If the calculated k value was equal, I checked if the value in midpoint-1 was equal to the value at the midpoint. If so, I configured the high point as midpoint and repeated. If midpoint-1 was less than the desired k, the midpoint was returned as the desired response.

Even with very large values ​​for k (10 or more digits), this approach works with O (n log (n)) speeds.

+6
source share
4 answers

Using this formula, the sequence of k values ​​given by fixed p and N = 1,2... does not decrease. This means that you can use the binary search option to find N given the desired k .

  • Start with N = 1 and calculate k .
  • Double N to k greater than or equal to your desired k to get the upper bound.
  • Do a binary search on the remaining interval to find k .
+1
source

Ok, this is fun.

We define f (i) = (p ^ i - 1) / (p - 1)

Write k in the form of a funny "base", where the position value i is this f (i).

You do this from the most significant to the least significant figure. So, first we find the largest j such that f (j) & lt = k. Then calculate the quotient and the remainder of k / f (j). Store the factor as q_j and the remainder as r. Now we calculate the quotient and the remainder of r / f (j-1). Save the factor as q_ {j-1} and the remainder again. Now we calculate the factor and the remainder of r / f (j-2). Etc.

This generates the sequence q_j, q_ {j-1}, q_ {j-2}, ..., q_1. (Note that the sequence ends with 1, not 0.) Then we calculate q_j * p ^ j + q_ {j-1} * p ^ (j-1) + ... q_1 * p. What is your N.

Example: k = 9, p = 3. So f (i) = (3 ^ i - 1) / 2. f (1) = 1, f (2) = 4, f (3) = 13. Thus, the largest j with f (j) <= 9 is equal to i = 2 with f (2) = 4. Take the factor and the remainder from 9/4. What is factor 2 (which is the figure in our 2nd place) and the remainder is from 1.

For this remainder of 1, find the quotient and the rest of 1 / f (1). The coefficient is 1, the remainder is zero, so we are done.

So q_2 = 2, q_1 = 1. 2 * 3 ^ 2 + 1 * 3 ^ 1 = 21, which is the correct N.

I have an explanation on paper why this works, but I'm not sure how to convey it in the text ... Note that f (i) answers the question: "How many factors p is in (p ^ i)!". As soon as you find the largest i, j such that j * f (i) is less than k, and understand what you really do is find the largest j * p ^ i is less than N, the rest of the species fall out of the wash, For example, in In our example p = 3 we get 4 p contributed by product 1-9, another 4 contributed by product 10-18, and another one capable of 21. These first two are simply a multiple of p ^ 2; f (2) = 4 tells us that every multiple p ^ 2 contributes another 4 p to the product.

[update]

The code always helps clarify. Save the following perl script as foo.pl and run it as foo.pl <p> <k> . Note that ** is the Perl exponent operator, bdiv computes the factor and remainder for BigInts (integers with unlimited precision), and use bigint tells Perl to use BigInts everywhere.

 #!/usr/bin/env perl use warnings; use strict; use bigint; @ARGV == 2 or die "Usage: $0 <p> <k>\n"; my ($p, $k) = map { Math::BigInt->new($_) } @ARGV; sub f { my $i = shift; return ($p ** $i - 1) / ($p - 1); } my $j = 0; while (f($j) <= $k) { $j++; } $j--; my $N = 0; my $r = $k; while ($r > 0) { my $val = f($j); my ($q, $new_r) = $r->bdiv($val); $N += $q * ($p ** $j); $r = $new_r; $j--; } print "Result: $N\n"; exit 0; 
+4
source

Why not try binary search for the answer using the second formula you mentioned?

You only need to consider the values ​​for N for which p divides N, because if it is not, then N! and (N-1)! are divided by the same cardinality p; therefore, N cannot be the smallest.

0
source

Consider

I = (p n )!

and ignore prime factors other than p. Result looks like

I = p n * p n-1 * p n-2 * ... * p * 1
I = p n + (n-1) + (n-2) + ... 2 + 1
I = p (n 2 + n) / 2

So, we are trying to find the smallest n such that

(n 2 + n) / 2> = k

which, if I remember the quadratic equation on the right, gives us

N = p n where n> = (sqrt (1 + 8k) -1) / 2


(PS Does anyone know how to show a radical symbol in markdowns?)

EDIT:

It is not right. Let me see if I can save him ...

-2
source

Source: https://habr.com/ru/post/890370/


All Articles