Calculating the number of prime factors - java

The following was the problem on codeforce
Two soldiers are playing a game. At the beginning first of them chooses a positive integer n and gives it to the second soldier. Then the second one tries to make maximum possible number of rounds. Each round consists of choosing a positive integer x > 1, such that n is divisible by x and replacing n with n / x. When n becomes equal to 1 and there is no more possible valid moves the game is over and the score of the second soldier is equal to the number of rounds he performed.
To make the game more interesting, first soldier chooses n of form a! / b! for some positive integer a and b (a ≥ b). Here by k! we denote the factorial of k that is defined as a product of all positive integers not large than k.
What is the maximum possible score of the second soldier?
Input
First line of input consists of single integer t (1 ≤ t ≤ 1 000 000) denoting number of games soldiers play.
Then follow t lines, each contains pair of integers a and b (1 ≤ b ≤ a ≤ 5 000 000) defining the value of n for a game.
Output
For each game output a maximum score that the second soldier can get.
So i tried to calculate the number of prime factors of n(as in the prime factorization of n).
Following is my my code but it fails for the test case
a=5000000 and b= 4999995
import java.util.Scanner;
import java.lang.*;
public class Main {
public static void main (String[] args) throws java.lang.Exception
{
// your code goes here
int count=0;
Scanner input=new Scanner(System.in);
int testcases=input.nextInt();
for(int m=1;m<=testcases;m++){
count=0;
long a=input.nextLong();
long b=input.nextLong();
double n=1;
for(double i=b+1;i<a+1;i++)
n=n*i;
//System.out.println(Math.sqrt(n));
for(int i=2;i<Math.sqrt(n);i++){
if(n%i==0){
while(n%i==0){
n=n/i;
count++;
}
}
}
if(n!=1) count++;
System.out.println(count);
}
}
}

In your case, a! / b! is
3,124,993,750,004,374,998,750,000,120,000,000
which is somewhat larger than 2^111. Only numbers up to 2^53 can be safely represented as an integer with a double value. If you use long, you can crank that up to 2^63, which still isn't enough.
You must either use BigInteger or you must change your approach: Instead of dividing the result of a! / b! into prime factors, divide the factors that contribute to the factorial and then merge the prime factor sets.
To illustrate with your example:
5000000 == 2^6 * 5^7
4999999 == 4999999
4999998 == 2 * 3 * 191 * 4363
4999997 == 43 * 116279
4999996 == 2^2 * 1249999
a! / b! == 2^9 * 3 * 5^7 * 43 * 191 * 4363 * 116279 * 1249999 * 4999999

As the input for a and b is small, we can create an array numOfPrime, which at index ith,
numOfPrime[i] = number of prime factor of i
So, we notice that numOfPrime[i] = 1 + numOfPrime[i/x] with x is any prime factor of i.
For simplicity, let x be the smallest prime factor of i, we can use Sieve of Eratosthenes to precalculate x for each i
int[]x = new int[5000001];
for(int i = 2; i < x.length; i++)
if(x[i] == 0)
for(int j = i + i; j < x.length; j+= i)
if(x[j] == 0)
x[j] = i;
int[]numOfPrime = new int[5000001];
for(int i = 2; i < x.length; i++)
if(x[i] == 0)
numOfPrime[i] = 1;
else
numOfPrime[i] = 1 + numOfPrime[i/x[i]];
You can take a look at my submission for this problem

Based on #m-oehm's answer:
int[] factors = new int[a-b];
for(int i=0;i<a-b;i++)
factors[i] = b+1+i;
boolean done = false;
int i = 2;
while(!done){
done = true;
for(int j=0; j<a-b; j++){
if(i>Math.sqrt(factors[j]) && factors[j]!=1){ // factors[j] is prime
factors[j] = 1;
count++;
}else{
while(factors[j]%i==0){ // divide factors[j] by i as many times as you can
factors[j]/=i;
count++;
}
}
if(factors[j]!=1) // if all factors have reach 1, you're done
done = false;
}
i++;
}

Related

Having trouble understanding logic behind testing if numbers are prime or not

/**
* The isPrime method iterates through every number in the range of 1 - 100 and adds every prime number to a
list in the file created by the user
* #param filename The file that numbers will be added to
*/
public static void isPrime(String filename) throws IOException
{
boolean status = true; // tells method if number is prime or not (if status = true, number is prime)
// opens up previously-created file for writing
FileWriter fwriter = new FileWriter(filename, true);
PrintWriter outputFile = new PrintWriter(fwriter);
for (int i = 1; i <= 100; i++)
{
// check if each number is prime
status = checkPrime(i);
if (status == true && i != 1)
{
outputFile.println(i);
}
}
outputFile.close();
}
/**
* The checkPrime method tests each number passed in as a parameter to see if it is prime
* #param num Integer to be tested
* #return Returns a boolean value of either true or false
*/
public static boolean checkPrime(int num)
{
int remainder; // used to test whether number is prime or not
for (int j = 2; j < num; j++)
{
remainder = num % j;
if (remainder == 0)
{
return false;
}
}
return true;
}
So this is a segment from my assignment. The code runs, but what I need help with is understanding the logic of why the 2nd method, checkPrime() works. I realize it's probably obvious, but I'm a new cs student, so if anyone is willing to explain why this works to me I'd appreciate it.
The % operator is the remainder operator. It is interating from 2 to num to see if the prime is divisible by any of those numbers. As soon as it is, it can't be a prime so it returns false. If finished and no divisor, it returns true.
But there is a more efficient way. Only divide the candidate number num by values staring with 2 up to the square root of num. Think about it, if there is no remainder up to that point, then no other number from the square root of num to num will divide it.
So first check for divisibility by 2. Then starting with 3 by just the odd numbers.
So the method would look like this.
public static boolean checkPrime(int num)
{
int remainder; // used to test whether number is prime or not
if(num % 2 == 0) {
return false;
}
for (int j = 3; j < (int)Math.sqrt(num)+1; j+=2)
{
remainder = num % j;
if (remainder == 0)
{
return false;
}
}
return true;
}
By definition, a prime number is a number that is only divisible by 1 or itself. For a number to be divisible the remainder of division should be 0.
Examples
5 is prime as it's only divisible by itself and 1:
5/5=1 remainder 0
5/4=1 remainder 1
5/3=1 remainder 2
5/2=2 remainder 1
5/1=5 remainder 0
While 4 is not prime because it's also divisible by 2:
4/4=1 remainder 0
4/3=2 remainder 1
4/2=2 remainder 0
4/1=4 remainder 0
The operator % is used to calculate the remainder 5%2=1.
Using this operator we can loop through all the numbers between 2 and num, for (int j = 2; j < num; j++) (we don't want to check 1 and num itself) and check the remainder, if (remainder == 0). Once remainder is equal to 0, the loop is broken and false is returned meaning the number is not prime. Otherwise, the loop finishes and the method returns true signalling that the number is prime.

Prime Factorization With Exponents In Java

I'm trying to write a java code that displays the prime factorization of a number in two forms: multiplied out and multiplied out with exponents. For example, the proper output would look like this:
Enter a number
100
The prime factorization of 100 is:
100 = 2 * 2 * 5 * 5
100 = 2^2 * 5^5
Except my current code only outputs this:
Enter a number
100
The prime factorization of 100 is:
100 = 2 2 5 5
Here's what my code looks like:
import java.util.Scanner;
public class Factorization {
public static void main(String[] args) {
Scanner keyboard = new Scanner(System.in);
// user inputs variables here
System.out.println("Enter a number");
long n = keyboard.nextLong();
System.out.println("The prime factorization of " + n + " is: ");
System.out.print(n+" = ");
// solution for 1 as an input
if(n==1){
System.out.println("1");
}
// for each potential factor
for (long factor = 2; factor*factor <= n; factor++) {
// if factor is a factor of n, repeatedly divide it out
while (n % factor == 0) {
System.out.print(factor + " ");
n = n / factor;
}
}
// if biggest factor occurs only once, n > 1
if (n > 1){
System.out.println(n);
} else {
System.out.println();
}
}
}
How can I make it give the proper output?
Thank you so much!
Printing out the first form is easy, and would just require a slight modification to your code so that it would print out the *. The second form, however, is a bit more tricky as you can't just directly print out the factors as you obtain them, since you need to count how many times each one occurs to know their exponent. There are a few different ways you could do this, but I thought the simplest would be to use 2 ArrayLists. One of these ArrayLists would contain the bases, while the other would contain the exponents for each base. This is my implementation, and I added some comments for clarification.
import java.util.Scanner;
import java.util.ArrayList;
public class Factorization{
public static void main(String[] args) {
Scanner keyboard = new Scanner(System.in);
// user inputs variables here
System.out.println("Enter a number");
long n = keyboard.nextLong();
long m = n;
System.out.println("The prime factorization of " + n + " is: ");
System.out.print(n+" = ");
ArrayList<Long> bases = new ArrayList<Long>(); //ArrayList containing each unique factor
ArrayList<Long> exponents = new ArrayList<Long>(); //ArrayList containing exponents, or the amount of times that factor is multiplied
// solution for 1 as an input
if(n==1){
System.out.println("1");
}
// for each potential factor
for (long factor = 2; factor*factor <= n; factor++) {
// if factor is a factor of n, repeatedly divide it out
while (n % factor == 0) {
n = n / factor;
if (!bases.contains(factor)){ //if the factor is not already in the bases list, it's unique and should be added
bases.add(factor);
exponents.add(1L);
}
else{ //if the factor is already in the bases list, increment its exponent by 1
exponents.set(bases.indexOf(factor), exponents.get(bases.indexOf(factor)) + 1);
}
}
}
// if biggest factor occurs only once, n > 1
if (n > 1){
if (!bases.contains(n)){
bases.add(n);
exponents.add(1L);
}
else{
exponents.set(bases.indexOf(n), exponents.get(bases.indexOf(n)) + 1);
}
}
//printing out the first form
for (int i = 0; i < bases.size(); i++)
{
for (int j = 0; j < exponents.get(i); j++) //each base is printed out an amount of times equal to its exponent
{
if (i != 0 || j != 0) //making sure we don't print * before the first base
{
System.out.print(" * ");
}
System.out.print(bases.get(i));
}
}
System.out.println();
System.out.print(m+" = ");
//printing out the second form
for (int i = 0; i < bases.size(); i++)
{
if (i >= 1) //making sure we don't print * before the first base
{
System.out.print(" * ");
}
System.out.print(bases.get(i) + "^" + exponents.get(i));
}
}
}
If you want to learn more about ArrayLists, I recommend you check out the official Java documentation on it here: https://docs.oracle.com/javase/8/docs/api/java/util/ArrayList.html.
I hope this helps.

Significant numbers - arithmetic average of proper divisors is not bigger than root of that number

The task seems pretty easy - on input I get number of tests (numOfTests), then two numbers (downBorder, upBorder) and I have to find how many numbers between those numbers (downBorder, upBorder) are significant numbers where significant number is a number which arithmetic average of proper divisors(all divisors except one and the same number) are smaller or equal than square root of that number.
I wrote the code and probably it works however it's too slow.
My code:
import java.io.BufferedReader;
import java.io.InputStreamReader;
public class Main {
public static void main(String[] args) throws java.lang.Exception
{
BufferedReader bf = new BufferedReader(new InputStreamReader(System.in)); //faster than Scanner
int numOfTests = Integer.parseInt(bf.readLine());
for(int i = 0; i < numOfTests; i++)
{
String[] borders = bf.readLine().split(" ");
long downBorder = Long.parseLong(borders[0]);
long upBorder = Long.parseLong(borders[1]);
//System.out.println(String.format("down: %s, up: %s", downBorder, upBorder));
System.out.println(countNumberOfSignificantNumbers(downBorder, upBorder));
}
}
/**
* print numbers of significant numbers - (arithmetic average of all divisors that is not bigger than root of that number)
* e.g 4 is significant but 6 is not
* #param downBorder
* #param upBorder
*/
private static int countNumberOfSignificantNumbers(Long downBorder, Long upBorder) {
int numberOfSignificantNumbers = 0;
for(Long i = downBorder; i <= upBorder; i++)
{
if(i%2 != 0)
continue;
else
{
double avgOfProperDivisors = getAvgArithOfSumOfNumberDividers(i);
if(avgOfProperDivisors != 0 && avgOfProperDivisors <= Math.sqrt(i))
numberOfSignificantNumbers++;
}
}
return numberOfSignificantNumbers;
}
/**
* method returns the arithemtic average of all proper divisors (all divisors except one and number itself)
* #param number
* #return
*/
public static double getAvgArithOfSumOfNumberDividers(Long number)
{
long maxD = number/2;
long sum=0;
long numOfDivs = 0;
for(long i = 2; i <= maxD; i++)
{
if(number % i == 0)
{
numOfDivs++;
sum += i;
}
}
return (numOfDivs > 0) ? (double)sum/numOfDivs : 0;
}
}
The bottleneck in this task is counting average of divisors. How can I make it better and faster?
Example input:
2
4 6
1 3
Example output:
1
0
Significant Number will always be a perfect square of a prime number like 4, 9, 25, 49, 121 etc. All you need to check is how many perfect square of a prime numbers lie between upBorder and downBorder.
You can reduce the complexity of the loop from O(number) to O(sqrt(number)).
This is based on the observation that if number is divisible by i, then it is also divisible by number/i. Given this, you can count the two divisors at once; given that the sparsity of the divisors increases as the number increases (i.e. the number of numbers you have to check before finding a divisor), you can save a lot of work in this way.
For example:
for (long i = 2; i*i <= n; ++i) {
if (n % i == 0) {
// i is a divisor, so increment the counters.
numOfDivs++; sum += i;
long c = n / i;
if (c != i) {
// c is a distinct divisor from i, so also increment the counters.
numOfDivs++; sum += c;
}
}
}
For example, 10 = 5*2. This approach finds a divisor when i=2, meaning that c=5. It can stop checking after i=3. In contrast, checking while i<=10/2 will stop checking after i=5.
As the number increases, the difference becomes far greater. For example, with number==1000, you check 499 numbers with i<=1000/2, but just 30 with i*i <= 1000.

Represent an Integer as a sum of Consecutive positive integers

I am writing code for counting the number of ways an integer can be represented as a sum of the consecutive integers. For Example
15=(7+8),(1+2+3+4+5),(4+5+6). So the number of ways equals 3 for 15.
Now the input size can be <=10^12. My program is working fine till 10^7(i think so, but not sure as i didnt check it on any online judge. Feel free to check the code for that)
but as soon as the i give it 10^8 or higher integer as input. it throws many runtime exceptions(it doesnt show what runtime error). Thanks in advance.
import java.io.*;
//sum needs to contain atleast 2 elements
public class IntegerRepresentedAsSumOfConsecutivePositiveIntegers
{
public static long count = 0;
public static void main(String[] args) throws IOException
{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
long num = Long.parseLong(br.readLine()); //Enter a number( <=10^12)
driver(num);
System.out.println("count = " + count);
}
public static void driver(long num)
{
long limit = num / 2;
for(long i = 1 ; i <= limit ; i++)
{
func(i,num);
}
}
public static void func(long i,long num)
{
if(i < num)
{
func(i + 1,num - i);
}
else if(i > num)
{
return;
}
else
{
count++;
}
}
}
Use some math: if arithmetic progression with difference 1 starts with a0 and contains n items, then its sum is
S = (2 * a0 + (n-1))/2 * n = a0 * n + n * (n-1) / 2
note that the second summand rises as quadratic function. So instead of checking all a0 in range S/2, we can check all n is smaller range
nmax = Ceil((-1 + Sqrt(1 + 8 * S)) / 2)
(I used some higher approximation).
Just test whether next expression gives integer positive result
a0 = (S - n * (n - 1) / 2) / n
Recursive function isn't suitable when you have big input size like your case.
The maximum depth of the java call stack is about 8900 calls and sometimes only after 7700 calls stack overflow occurs so it really depends on your program input size.
Try this algorithm I think it worked for your problem:
it will work fine until 10^9 after that it will take much more time to finish running the program.
long sum = 0;
int count = 0;
long size;
Scanner in = new Scanner(System.in);
System.out.print("Enter a number <=10^12: ");
long n = in.nextLong();
if(n % 2 != 0){
size = n / 2 + 1;
}
else{
size = n / 2;
}
for(int i = 1; i <= size; i++){
for(int j = i; j <= size; j++){
sum = sum + j;
if(sum == n){
sum = 0;
count++;
break;
}
else if(sum > n){
sum = 0;
break;
}
}
}
System.out.println(count);
Output:
Enter a number <=10^12: 15
3
Enter a number <=10^12: 1000000000
9
BUILD SUCCESSFUL (total time: 10 seconds)
There's a really excellent proof that the answer can be determined by solving for the unique odd factors (Reference). Essentially, for every odd factor of a target value, there exists either an odd series of numbers of that factor multiplied by its average to produce the target value, or an odd average equal to that factor that can be multiplied by double an even-sized series to reach the target value.
public static int countUniqueOddFactors(long n) {
if (n==1) return 1;
Map<Long, Integer> countFactors=new HashMap<>();
while ((n&1)==0) n>>>=1; // Eliminate even factors
long divisor=3;
long max=(long) Math.sqrt(n);
while (divisor <= max) {
if (n % divisor==0) {
if (countFactors.containsKey(divisor)) {
countFactors.put(divisor, countFactors.get(divisor)+1);
} else {
countFactors.put(divisor, 1);
}
n /= divisor;
} else {
divisor+=2;
}
}
int factors=1;
for (Integer factorCt : countFactors.values()) {
factors*=(factorCt+1);
}
return factors;
}
As #MBo noted, if a number S can be partitioned into n consecutive parts, then S - T(n) must be divisible by n, where T(n) is the n'th triangular number, and so you can count the number of partitions in O(sqrt(S)) time.
// number of integer partitions into (at least 2) consecutive parts
static int numberOfTrapezoidalPartitions(final long sum) {
assert sum > 0: sum;
int n = 2;
int numberOfPartitions = 0;
long triangularNumber = n * (n + 1) / 2;
while (sum - triangularNumber >= 0) {
long difference = sum - triangularNumber;
if (difference == 0 || difference % n == 0)
numberOfPartitions++;
n++;
triangularNumber += n;
}
return numberOfPartitions;
}
A bit more math yields an even simpler way. Wikipedia says:
The politeness of a positive number is defined as the number of ways it can be expressed as the sum of consecutive integers. For every x, the politeness of x equals the number of odd divisors of x that are greater than one.
Also see: OEIS A069283
So a simple solution with lots of room for optimization is:
// number of odd divisors greater than one
static int politeness(long x) {
assert x > 0: x;
int p = 0;
for (int d = 3; d <= x; d += 2)
if (x % d == 0)
p++;
return p;
}

Prime Number Finder has a mind of its own?

I am making a prime number finder, that would find the prime numbers for a given number that the user inputs. What I have now seems to either miss primes, or add non-primes to the ArrayList. My code seems logical to me, and I'm confused as to why this is happening. Can anyone tell me what I am doing wrong? Or maybe a simpler way to do this (I feel like I am over-complicating)? Some examples of errors would be: Enter 21, only 3 shows as a prime. Enter 11000, 25 and 55 show up (not prime obviously). Thanks in advance!
import java.util.*;
public class PrimeFactors {
public static void main(String args[]) {
long num;
Scanner in = new Scanner(System.in);
System.out.println("\n\n\nThis program finds the prime factors of a given number.\n");
System.out.print("Please enter the number: ");
num = in.nextLong();
System.out.println("\nThe prime factors are: " + primeFactor(num) + "\n");
}
public static ArrayList<Long> primeFactor(long n) {
long output = 0;
long guess = 2;
ArrayList<Long> primeFactors = new ArrayList<Long>();
while (guess <= n) {
long primes = 0;
long i = 2;
long x = 0;
long rt = 1;
long duplicate = 0;
output = n % guess;
// Finds the sqrt.
while (x <= n) {
x = rt * rt;
rt++;
}
// Finds odd factors.
if ((output == 0) && (guess % 2 != 0)) {
// This divides the odd factor by an incrementing number that is not 1 or the number itself.
while (i < rt) {
primes = primes + (guess % i);
// If the sum of the remainders to the division is not 0, then the number is prime.
// I used duplicate to make sure it didn't just go through once and count as prime.
if (primes != 0){
// There were duplicates, so I added them for the division later.
duplicate = duplicate + guess;
// This was used to wait for the while loop to finish, then find if the amount of times the guess went through was equal to its value - 1 and another 1 for the final number (primes are only divisible by one and itself).
if (i == (factors - 1)) {
if ((duplicate / guess) == (guess- 2)) {
primeFactors.add(guess);
}
}
}
i++;
}
}
guess++;
}
return primeFactors;
}
}
The math and logic you're doing here is very strange and I don't quite follow what's happening.
To that end, I would vote +1 for making the code simpler. This can be done with two simple methods. The first method will find factors for a number and run them through a prime checker. If they are a factor and pass the prime check, they get added to the array.
Bonus points: increase the speed of the algorithm by only searching through the bottom half of each of the factor checker and prime checker. Logic being that any value beyond half a number cannot be a factor of that number.
More bonus points for speed, increment by 2 skipping all multiples of 2, since they are automatically not prime. Good luck!
import java.util.ArrayList;
import java.util.Scanner;
/***************************************************
*
* #file: PrimeFactors.java
* #date: Mar 17, 2013
* #author: AaronW
*/
/**
*
* #author AaronW
*/
public class PrimeFactors {
public PrimeFactors() {
}
/**
*
* #param args
*/
public static void main(String[] args) {
long num;
Scanner in = new Scanner(System.in);
System.out.println("\n\n\nThis program finds the prime factors of a given number.\n");
System.out.print("Please enter the number: ");
num = in.nextInt();
System.out.println("\nThe factors are: " + findFactors((double)num) + "\n");
}
public static ArrayList<Integer> findFactors(Double num) {
ArrayList<Integer> factors = new ArrayList<Integer>();
for (int x = 1; x <= num; x++) {
System.out.println("Testing " + num + " % " + x + " = " + num % x);
// First, let's see if a number is factor of your target number
if (num % x == 0) {
System.out.println(x + " is a factor");
// Now that we know it's a factor, let's test to see if it's prime
if (isPrime(x)) {
// If it's prime, add it to the ArrayList
System.out.println("And " + x + " is prime.");
factors.add(x);
} else {
System.out.println("But " + x + " is not prime.");
}
} else {
System.out.println(x + " is not a factor");
}
}
return factors;
}
public static boolean isPrime(double num) {
// Let's start by assuming everything is prime and try to prove that false
// If we fall through the loop without proving it false, we have a prime
boolean prime = true;
for (int x = 2; x < num; x++) {
// if our target number can be divided by any number between 1 and itself, it is not prime
if (num % x == 0) {
prime = false;
}
}
return prime;
}
}
For a start, instead of
long x = 0;
long z = 1;
while (x <= n) {
x = z * z;
z++;
}
while (j < z) {
You can just do this
z = (int) Math.Sqrt(n)
while (j <= z) {
Then for each j I would check if it divides n with no remainder.
If it divides n with no remainder, divide n by j and add j to the prime factors. Then instead of incrementing j, try the same j again, for instance for 9 you do 3 twice for its factors.
Anything more complex than that is unnecessary - you will try each j until it can divide into n no more, and you will always try primes before composites formed of those primes, so you know off the bat you'll end up with only prime factors.
OK, there are a few problems with your code:
j, x, j & n, poorly named variables make for hard work debugging.
Where are your System.out.println() calls so you can see what is going on in your code?
The square root of n would be a more optimal point to stop looking for prime up to n.
Can I suggest you look at this: http://en.wikipedia.org/wiki/Sieve_of_Eratosthenes for a rapid way of finding primes.
One suggestion to make the code simpler. In you primeFactors method, first findout is it a factor, which I believe you are already doing, then call another method to determine if this is a prime. If that is prime add to the list.
I'll give you some pseudo-code for a simple to implement (not efficient) algorithm:
the value to factorize is N
keep going until N is equal to one
start at 2 and find lowest number X that divides N evenly
X is one factor
N/X is your new N to factor
Your variable names are inconsistent. factors is particularly bad, as it is only a guess of a single factor. Call it guess instead.
The arithmetic you do with factors, primes, and dup are also strange. Why are you adding to dup or primes? Try being your own computer, and executing your algorithm for the number 12; you'll see that you don't have a correct algorithm at all.
You've foreclosed the possibility of repeated factors by incrementing factors at the end.

Categories

Resources