Mad Scientist

From programming_contest
Revision as of 19:12, 3 December 2015 by imported>Aam47
Jump to navigation Jump to search

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;
	}
	
	

}