Project Euler's, Problem #565

932 Views Asked by At

Project Euler's, Problem #565 states:

Let $\sigma(n)$ be the sum of the divisors of $n$. E.g. the divisors of $4$ are $1, 2$ and $4$, so $\sigma(4)=7$.

The numbers $n$ not exceeding $20$ such that $7$ divides $\sigma(n)$ are: $4, 12, 13$ and $20$, the sum of these numbers being $49$.

Let $S(n, d)$ be the sum of the numbers $i$ not exceeding $n$ such that $d$ divides $\sigma(i)$.

So $S(20, 7)=49$.

You are given: $S(10^6, 2017)=150850429$ and $S(10^9, 2017)=249652238344557$

Find $S(10^{11}, 2017)$

I have written up a program in Java that finds the solution to $S(20, 7)$ in about $0.001$ seconds on my computer. The same program takes a little over $7$ seconds to find the solution to $S(10^6, 2017)$. However, it seemingly takes forever to execute $S(10^9, 2017)$. I have not even bothered with trying to find $S(10^{11}, 2017)$ until I can come up with a much more efficient method.

Given that these are mathematical problems intended to be solved by a computer, I need to find and exploit something from math to vastly improve the running time of my program.

One of the first things that stood out to me when I saw this problem is that I used the divisor function and its multiplicative property before to come up with an elegant and very efficient method to solve a previous Project Euler program. So, I referenced the divisor function wiki article once more to find something that would help me, but I don't understand enough of the math to benefit from it.

I also utilized a well known algorithm that is taught in most Intro to Computer Science courses in order to efficiently find the divisors of each $n$ and to summate them.

The pseudocode for the algorithm I used is as follows:

1. Input an integer n
2. Set a variable named sum equal to 0
3. Set a variable named limit to be the sqrt(n)
3. Run a loop from i = 1 to  i <= limit
       if n is divisible by i, then add i to sum 
           if i does not equal (n / i), then add (n / i) to sum
4. Return the sum

To the extent of my knowledge, this algorithm is one of the quickest out there to find divisors of integers. I used this algorithm to implement the sum-of-divisors function in my program.

The next part is what I suspect is making the my code so inefficient. It follows the $S(n, d)$ function that Project Euler described. Here is the pseudocode for my implementation of $S(n, d)$:

1. Input an integer n 
2. Input an integer d
3. Set a variable named sumNums equal to 0
4. Run a loop from i = 1 to i <= n
       if d divides sumOfDivisors(i), then add i to sumNums
5. Return sumNums

So, my question is what mathematical fact(s) and/or theorems can I utilize to make my program find the solution expeditiously?