Product-Sum Numbers (88)
In Problem 88, we're asked to find numbers that can be represented both as a sum and product of a sequence of numbers.
We can reframe the question with more math notation like so: For every
is minimized. The final solution then the sum of all unique
Naive complexity
We have to iterate through 12,000 values of
Even for fixed
If we look at
- 1 × 12
- 2 × 6
- 3 × 4
At
- 1 × 1 × 12
- 1 × 2 × 6
- 1 × 3 × 4
- 2 × 2 × 3
We essentially have a triple loop here. That is not clever enough to solve this problem.
We have two ways to slice this problem:
- We iterate over all
and then try to find the matching . - We iterate over all
and see for which we can find a product-sum-match.
The way that the problem is phrased, it suggests to start with the first approach. As I found out the hard way, that doesn't work. Therefore we will cover the second approach first. You can read about the non-viability of the first approach further down.
Fixing n and looking for suitable k's
We can also look at all factorizations without fixing
Iterating over all factorizations that have at least two factors, we can compare the product and the sum. In case that the sum is smaller than the product, we can always pad with ones on both sides. If the sum is larger than the product, it is not a viable factorization.
Taking 8, we can factorize that into 2 × 4. But 2 + 4 is just 6, so we need to pad it with 1's:
Assuming that we have already checked all smaller
Similarly we do the factorization into 2 × 2 × 2 and realize that this also only yields 6. Hence we add more 1's again:
This gives us
The algorithm that we can generalize from this approach is:
- Iterate over all
from 2 to infinity … - Iterate over all factorizations
of … - If the factorization has only one element,
, skip that one. - Compute the sum over all factors,
. We know by construction that . - If
, we need to pad with many elements of 1. That increases exactly such that it is , and will be unchanged. - The number of elements in the decomposition is
. - If
, note the as the smallest possible for that because we have checked all smaller already.
- If the factorization has only one element,
- If we have 11,999 elements in our result, we have found an
for every and break out of the loop.
- Iterate over all factorizations
- Take the unique
and sum them up.
My Rust implementation runs in 123 ms.
Trying to use a fixed k
Let us now explore why using a fixed

We can then look at the products that we can form in these positions. The strong number now means the product, the lines indicate the sum. When both match, we have a candidate. We're looking for the match that is on the highest diagonal, meaning the smallest number.

From this, one can see that within each diagonal, the numbers get bigger. As this is monotonic, we should be able to bisect along the diagonal line and reduce the complexity from
All this is just

We don't need to keep all from one ring though, just the lexicographically smallest one is sufficient. And it seems that these can be represented in a pyramid of sorts, until the sum is 9 and the number of combinations grows faster. When the tuples are sorted lexicographically, their product seems to increase, as before.

These are cute drawings, but I am not sure whether any of this really helps.
Moving digits
Another idea that I had is that I could just decrease a number on the right and increase a number on the left. The constraint is that the numbers must not decrease from left to right in order to avoid duplicates. For

In order to reach (3, 3, 3), handling only adjacent numbers is not enough. We also need to move non-adjacent numbers. That makes the graph more complicated:

Because only working with adjacent numbers, the idea turns out to be more complicated.
Search tree
We can formulate this as a search tree, though. We pick all possible first numbers and then see which second numbers are viable and so on. This is the graph that get:

Using recursion, one could easily traverse all these options. At least for
I have done this and written a recursive function that will decompose the remainder further into a sum. The return value is a set of all possible products that can be formed given the desired sum
From