Mad Scientist: Difference between revisions
imported>Azd2 No edit summary |
imported>Aam47 No edit summary |
||
Line 1: | Line 1: | ||
==Introduction== | ==Introduction== | ||
Given two positive integers $n$ and $k$, find the biggest integer $i$ such that $k^{i}$ divides $n!$. Note that we are given the following bounds: $(2 ≤ n ≤ 1018, 2 ≤ k ≤ 1012)$. | |||
==Solutions== | |||
===Idea=== | |||
The main idea is to take advantage of unique prime factorization to write $k=p_{1}^{\alpha_{1}} ... p_{n}^{\alpha_{n}}$. After explicitly computing this factorization, the task is just to find the $p_{j}^{\alpha_{j}}$ which appears in $n!$ the least number of times $i$, and this $i$ will be the answer. To do this, it clearly suffices to compute the number of times $p_{i}$ appears in $n!$. To do this, we can just be careful about how we count. In other words, we do not have to explicitly compute $n!$ or its prime factorization. The rest of this section will deal with this counting.\\ | |||
Let $S$ be the number of times a given prime $p$ appears in $n!$, and let $l$ be the largest $l$ such that $p^{l}\le n$. Then I claim that | |||
\[ | |||
S = \sum_{i=1}^{l} \lfloor \frac{n}{p^{i}} \rfloor | |||
\] | |||
To see this, let $n_{i}$ be the number of integers $m \le n$ such that $i$ is the highest power of $p$ dividing $m$. Then | |||
\[ | |||
S = \sum_{i=1}^{l}in_{i} = n_{1} + n_{2} + n_{2} + \dots + n_{l} + \dots + n_{l} = \sum_{i=1}^{l}\sum_{k=i}^{l}n_{k} = \sum_{i=1}^{l}\lfloor \frac{n}{p^{i}} \rfloor | |||
\] | |||
Now that we know how to compute $S_{j}$ for each prime $p_{j}$, it is easy to compute $i$ by taking | |||
\[ | |||
i = \min_{j} \lfloor \frac{S_{j}}{\alpha_{j}} \rfloor | |||
\] | |||
===Runtime=== | ===Runtime=== | ||
Prime factorization can be done in $\sqrt{k}$, and computing $S$ takes $log_{p_{j}} n$ time for each $p_{j}$. An extremely rough upper bound on $j$ is $\sqrt{k}$, so that the overall runtime is bounded roughly by $\sqrt{k} log n$. | |||
===Code=== | ===Code=== | ||
Line 24: | Line 31: | ||
import java.util.Scanner; | import java.util.Scanner; | ||
public class DividingPowers { | |||
static Scanner in = new Scanner(System.in); | |||
public class | |||
public static void main(String[] args) { | |||
long caseNum=1; | |||
long a = in.nextLong(); | |||
for(long i = 0; i<a; i++){ | |||
long n = in.nextLong(); | |||
long k = in.nextLong(); | |||
long ans = largestPower(n,k); | |||
System.out.printf("%d\n", ans); | |||
caseNum++; | |||
} | |||
} | |||
public static long largestPower(long n, long k){ | |||
ArrayList<Long> primes = primeFactorization(k); | |||
long minAppearance = Long.MAX_VALUE; | |||
for(int i = 0; i <(primes.size()+1)/2; i++){ | |||
long p = primes.get(i*2); | |||
long temp = numAppearances(n,p); | |||
if(minAppearance> temp/primes.get(i*2+1)){ | |||
minAppearance = temp/primes.get(i*2+1); | |||
} | |||
} | |||
return minAppearance; | |||
} | |||
private static long numAppearances(long n, Long p) { | |||
long numAppear=0; | |||
int i = 0; | |||
while(Math.pow(p, i)<=n){ | |||
i++; | |||
} | |||
i--; | |||
for(int j = 1; j<=i; j++){ | |||
numAppear+=n/((long)Math.pow(p, j)); | |||
} | |||
return numAppear; | |||
} | |||
private static ArrayList<Long> primeFactorization(long k) { | |||
ArrayList<Long> primes = new ArrayList<Long>(); | |||
for(long i = 2; i<=Math.sqrt(k); i++){ | |||
long j = 0; | |||
while(k%((long)Math.pow(i, j))==0){ | |||
j++; | |||
} | |||
if(j>1){ | |||
primes.add(i); | |||
primes.add(j-1); | |||
ArrayList<Long> restPrimes = primeFactorization((long)(k/(Math.pow(i, j-1)))); | |||
i=k; | |||
for(Long a : restPrimes){ | |||
primes.add(a); | |||
} | |||
} | |||
} | |||
if(primes.size()==0&&k!=1){ | |||
primes.add(k); | |||
primes.add((long) 1); | |||
} | |||
return primes; | |||
} | |||
} | } | ||
</syntaxhighlight> | </syntaxhighlight> | ||
Revision as of 19:12, 3 December 2015
Introduction
Given two positive integers $n$ and $k$, find the biggest integer $i$ such that $k^{i}$ divides $n!$. Note that we are given the following bounds: $(2 ≤ n ≤ 1018, 2 ≤ k ≤ 1012)$.
Solutions
Idea
The main idea is to take advantage of unique prime factorization to write $k=p_{1}^{\alpha_{1}} ... p_{n}^{\alpha_{n}}$. After explicitly computing this factorization, the task is just to find the $p_{j}^{\alpha_{j}}$ which appears in $n!$ the least number of times $i$, and this $i$ will be the answer. To do this, it clearly suffices to compute the number of times $p_{i}$ appears in $n!$. To do this, we can just be careful about how we count. In other words, we do not have to explicitly compute $n!$ or its prime factorization. The rest of this section will deal with this counting.\\
Let $S$ be the number of times a given prime $p$ appears in $n!$, and let $l$ be the largest $l$ such that $p^{l}\le n$. Then I claim that \[ S = \sum_{i=1}^{l} \lfloor \frac{n}{p^{i}} \rfloor \] To see this, let $n_{i}$ be the number of integers $m \le n$ such that $i$ is the highest power of $p$ dividing $m$. Then \[ S = \sum_{i=1}^{l}in_{i} = n_{1} + n_{2} + n_{2} + \dots + n_{l} + \dots + n_{l} = \sum_{i=1}^{l}\sum_{k=i}^{l}n_{k} = \sum_{i=1}^{l}\lfloor \frac{n}{p^{i}} \rfloor \]
Now that we know how to compute $S_{j}$ for each prime $p_{j}$, it is easy to compute $i$ by taking \[ i = \min_{j} \lfloor \frac{S_{j}}{\alpha_{j}} \rfloor \]
Runtime
Prime factorization can be done in $\sqrt{k}$, and computing $S$ takes $log_{p_{j}} n$ time for each $p_{j}$. An extremely rough upper bound on $j$ is $\sqrt{k}$, so that the overall runtime is bounded roughly by $\sqrt{k} log n$.
Code
Solution - Java
import java.util.ArrayList;
import java.util.Scanner;
public class DividingPowers {
static Scanner in = new Scanner(System.in);
public static void main(String[] args) {
long caseNum=1;
long a = in.nextLong();
for(long i = 0; i<a; i++){
long n = in.nextLong();
long k = in.nextLong();
long ans = largestPower(n,k);
System.out.printf("%d\n", ans);
caseNum++;
}
}
public static long largestPower(long n, long k){
ArrayList<Long> primes = primeFactorization(k);
long minAppearance = Long.MAX_VALUE;
for(int i = 0; i <(primes.size()+1)/2; i++){
long p = primes.get(i*2);
long temp = numAppearances(n,p);
if(minAppearance> temp/primes.get(i*2+1)){
minAppearance = temp/primes.get(i*2+1);
}
}
return minAppearance;
}
private static long numAppearances(long n, Long p) {
long numAppear=0;
int i = 0;
while(Math.pow(p, i)<=n){
i++;
}
i--;
for(int j = 1; j<=i; j++){
numAppear+=n/((long)Math.pow(p, j));
}
return numAppear;
}
private static ArrayList<Long> primeFactorization(long k) {
ArrayList<Long> primes = new ArrayList<Long>();
for(long i = 2; i<=Math.sqrt(k); i++){
long j = 0;
while(k%((long)Math.pow(i, j))==0){
j++;
}
if(j>1){
primes.add(i);
primes.add(j-1);
ArrayList<Long> restPrimes = primeFactorization((long)(k/(Math.pow(i, j-1))));
i=k;
for(Long a : restPrimes){
primes.add(a);
}
}
}
if(primes.size()==0&&k!=1){
primes.add(k);
primes.add((long) 1);
}
return primes;
}
}