Wednesday, October 28, 2015

Problem 29 : Distinct Powers

Distinct powers

Problem 29

Consider all integer combinations of ab for 2 ≤ a ≤ 5 and 2 ≤ b ≤ 5:
22=4, 23=8, 24=16, 25=32
32=9, 33=27, 34=81, 35=243
42=16, 43=64, 44=256, 45=1024
52=25, 53=125, 54=625, 55=3125
If they are then placed in numerical order, with any repeats removed, we get the following sequence of 15 distinct terms:
4, 8, 9, 16, 25, 27, 32, 64, 81, 125, 243, 256, 625, 1024, 3125
How many distinct terms are in the sequence generated by ab for 2 ≤ a ≤ 100 and 2 ≤ b ≤ 100?
                                                                                                       (https://projecteuler.net/problem=29)
You know what. If you struggled with this problem, here is a cheat that you can follow.

It's not actual cheating, but there is no complicated algorithms used in this problem like my other solutions in this blog. I'll tell you one thing, and you're all-set.

In Java, there is a type of list called HashSet which only stores distinct values.

For example, I will add 1, 2, 2, 2, 4, 7, and 7 into an ArrayList.

index 0 1 2 3 4 5 6
data 1 2 2 2 4 7 7

Now, I will add 1, 2, 2247, and 7 into an HashSet.

index ? ? ? ?
data 1 2 4 7

We cannot directly know in what order the HashSet stores its data, yet we find that all the duplicate values were automatically eliminated, or not stored from the beginning.

And this is why it fulfills our goal: how many distinct terms are in the sequence.

Set<BigInteger> list1 = new HashSet<BigInteger>();
  
for (int a = 2; a <= 100; a++)
{
    for (int b = 2; b <= 100; b++)
    {
     list1.add(BigInteger.valueOf(a).pow(b));
    }
}
System.out.println(list1.size());

We will get 38.04139449846139 ms, or 0.038 seconds. Decent efficiency.

And I will tell you now that I lied. There is actually one more cheat that we can use here.

When we reach some numbers extremely large like ab where 2 ≤ a, b ≤ 100, they are large enough that each number becomes extremely unique numbers.

So do we need precision? Does it matter that 123456789 is different from 123456788?

... Not really. It's just large number that is about 1.23 x 108. That's all we need.

Therefore, I will simply use double instead of BigInteger.

I guarantee that double will provide enough precision for our calculation for this problem.

Set<Double> list = new HashSet<Double>();
  
for (int a = 2; a <= 100; a++)
{
    for (int b = 2; b <= 100; b++)
    {
        list.add(Math.pow(a, b));
    }
}
System.out.println(list.size());

Yay! 8.5 millisecond!

Answer is 9183
Execution time is 8.553895 ms
Source Code: https://github.com/Ainodyne/Project-Euler/blob/master/Problem029.java


Monday, October 12, 2015

Problem 23 : Non-Abundant Sums

Non-abundant sums

Problem 23

A perfect number is a number for which the sum of its proper divisors is exactly equal to the number. For example, the sum of the proper divisors of 28 would be 1 + 2 + 4 + 7 + 14 = 28, which means that 28 is a perfect number.

A number n is called deficient if the sum of its proper divisors is less than n and it is called abundant if this sum exceeds n.

As 12 is the smallest abundant number, 1 + 2 + 3 + 4 + 6 = 16, the smallest number that can be written as the sum of two abundant numbers is 24. By mathematical analysis, it can be shown that all integers greater than 28123 can be written as the sum of two abundant numbers. However, this upper limit cannot be reduced any further by analysis even though it is known that the greatest number that cannot be expressed as the sum of two abundant numbers is less than this limit.

Find the sum of all the positive integers which cannot be written as the sum of two abundant numbers.
                                                                                                       (https://projecteuler.net/problem=23)

A few days ago, we had a discussion about amicable numbers.

And I mentioned about 6, which was "amicable" to itself, and now it appears again.

As the problem explains, s(6) = 1 + 2 + 3 = 6, which means it is "amicable" number to itself, or we mathematically call it a perfect number.

Numbers like 12, where s(12) = 1 + 2 + 3 + 4 + 6 = 16 > 12, is called an abundant number.

 s(n)=sigma(n)-n>n,

Personally this problem was one of some tedious problems in Project Euler.

I couldn't come up with an efficient algorithm (even though I met the Project Euler standard efficiency: 1 minute), so I ended up using sieve, reducing redundancies, and half-cutting the limit in order to meet my personal premise in problem-solving (under 1 second).

Here is my algorithm.

The problem hints us that the limit is 28123, and that the smallest abundant number is 12, and therefore the sum of two abundant numbers is 24.

From now on, I will just call such integers that is the sum of two abundant numbers abby numbers.
(for convenience)

(This term is not a defined mathematical term, so don't use it anywhere else.)

We are going to find the sum of non-abby numbers.

Here is my algorithm for abundant number sieve:

public static boolean[] sieveAbundance(int limit)
{
    boolean[] abun = new boolean[limit + 1];
    for (int i = 12; i <= limit; i++)
    {
        if (!abun[i])
        {
            if (abun[i] = isAbundant(i))
            {
                for (int j = i; j <= limit; j += i)
                    abun[j] = true;
            }
        }
    }
    return abun;
}

Overall similar principle to Sieve of Eratosthenes (problem 10), yet I have one thing to point out.

Once the number is proven to be an abundant number, then its multiples are all abundant numbers.

The proof is simple. If the sum of the proper divisors of a certain number is already greater than itself, then doubling the number will produce twice as much proper divisors for the number (and the sum of the values will definitely exceeds the original number), and the number will clearly be an abundant number.

Next, we need to determine if the number is an abundant number.

public static boolean isAbundant(int n)
{
    int original = n;
    int sum = 1;
 
    if (n % 2 == 0)
    {
        int temp = 1;
        for (int mult = 2; n % 2 == 0; n /= 2, mult *= 2)
            temp += mult;
        sum *= temp;
    }
    for (int i = 3, end = (int)Math.sqrt(n); i <= end; i += 2)
    {
        if (n % i == 0)
        {
            int temp = 1;
            for (int mult = i; n % i == 0; n /= i, mult *= i)
                temp += mult;
            sum *= temp;
            end = (int)Math.sqrt(n);
        }
    }
    if (n != 1) sum *= 1 + n;
    return original + original < sum;
}

In this algorithm, I divided the division part into [2] and [odd numbers].
(By checking the divisibility by 2, I can skip rest of even numbers.)

And the logic behind the algorithm is written here:

Let's say our number is 36. Its proper divisors are 1, 2, 3, 4, 6, 9, 12, 18.

The sum is 1 + 2 + 3 + 4 + 6 + 9 + 12 + 18 = 55 > 36. It is an abundant number.

Prime factorization: 36 = 22 x 32.

With 22, we can produce 1, 2, and 4. Let's add them up. 1 + 2 + 4 = 7.

Now, we have 32. We can produce 1, 3, and 9. Let's add them up. 1 + 3 + 9 = 13.

Let's multiply those two sums. 7 * 13 = 91.

91 minus the original number 36 equals 91 - 36 = 55. The sum of the proper divisors.

What?! How could that happen??

Ok, here is the proof.

36 20 (A) 21 (B) 22 (C)
30 (D) 1 2 4
31 (E) 3 6 12
32 (F) 9 18 36

where each un-bolded numbers in the table is the multiplication of two elements.

For example, 18 in the box is the product of 21 x 32, or column x row.

Instead of adding all the element manually, we are going to use multiplication of polynomials in order to quickly get the sum of the factors. (including itself)

We want to get AD + AE + AF + BD + BE + BF + CD + CE + CF, which we can factor out into (A + B + C)(D + E + F). And this is (1 + 2 + 4)(1 + 3 + 9) = 91, which I did above.

Because this is the sum of every factor, we need to subtract the original number in order to get the sum of the proper factors.

Last step is to find abby number from the information on abundant numbers we calculated.

Because it tends to have abundant numbers in bigger numbers than small numbers, the algorithm will start finding the abundant pairs from the biggest to smallest. For example, if we want to check if 72 is abby number, we will divide it into half and start with (36, 36) pair, which is more likely than (1, 71) pair.

public static boolean isSumOfTwoAbundant(int n)
{
    for (int i = n / 2; i >= 12; i--)
        if (isAbundant[i] && isAbundant[n - i]) return true;
    return false;
}

and WE ARE FINALLY DONE!

int sum = 0;
for (int i = 1; i <= LIMIT; i++)
{
    if (!isSumOfTwoAbundant(i)) sum += i;
}
System.out.println(sum);


Answer is 4179871
Execution time is 28.948803 ms
Source Code: https://github.com/Ainodyne/Project-Euler/blob/master/Problem023.java