71 lines
2.3 KiB
Typst
71 lines
2.3 KiB
Typst
#let post_slug = "pe-p1"
|
|
#let post_preview_image = "image.png"
|
|
#let post_summary = "General solution to Project Euler Problem 1"
|
|
#let post_date = "2026-07-29"
|
|
|
|
= Project Euler Problem 1
|
|
|
|
== Statement
|
|
If we list all the natural numbers below $10$ that are multiples of $3$ or $5$, we get $3, 5, 6,$ and $9$. The sum of these multiples is $23$. Find the sum of all the multiples of $3$ or $5$ below $1000$.
|
|
|
|
== Solution
|
|
|
|
Suppose the base numbers were $2$ and $3$ below $10$ so $9$, they would create duplicates, ie $6$ is counted twice. Therefore take the sum of each multiple to the limit, and one time remove the numbers counted twice:
|
|
|
|
#text(fill: white, html.frame(
|
|
$
|
|
&2+4+6+8+3+cancel(6)+9 = 32\
|
|
&sum_(i=1)^(floor(9/(2)))2i + sum_(i=1)^(floor(9/(3))) 3i - sum_(i=1)^(floor(9/(6))) 6i \
|
|
= 2&sum_(i=1)^(floor(9/(2)))2i + 3sum_(i=1)^(floor(9/(3))) i - 6sum_(i=1)^(floor(9/(6))) i \
|
|
= 2&sum_(i=1)^4 i + 3sum_(i=1)^3 i - 6sum_(i=1)^(1) i\
|
|
= 2& (4(5))/2 + 3 (3(4))/2 - 6 (1(2))/2\
|
|
= 3&2
|
|
$
|
|
))
|
|
|
|
This revealed a general solution, for base numbers $n, m$ below $L$:
|
|
|
|
#text(fill: white, html.frame(
|
|
$
|
|
f(n,m,L) =&n sum_(i=1)^floor((L-1)/n) i + m sum_(i=1)^floor((L-1)/m) i- n m sum_(i=1)^floor((L-1)/(n m))i \
|
|
"Define "&a = floor((L-1)/n), b = floor((L-1)/m), c = floor((L-1)/(n m)) \
|
|
=> f(n,m,L) =& (n a(a+1) + m b(b+1) - n m (c)(c+1))/2
|
|
$
|
|
))
|
|
|
|
Testing this as code:
|
|
```py
|
|
>>> def f(n,m,L):
|
|
... a = floor((L-1)/n)
|
|
... b = floor((L-1)/m)
|
|
... c = floor((L-1)/(n*m))
|
|
... return ((n*a*(a+1)) + (m*b*(b+1)) - (n*m*c*(c+1)))/2
|
|
...
|
|
>>> f(2,3,10)
|
|
44.0
|
|
>>> f(3,5,10)
|
|
23.0
|
|
```
|
|
|
|
This general solution passes the two tests above.
|
|
|
|
```py
|
|
>>> f(3,5,1000)
|
|
233168.0
|
|
```
|
|
|
|
Testing against the question, this result is successful. But what about for more than 2 numbers? How can this be approached?
|
|
|
|
Given a set $A$ of base numbers, a multiple would be counted once for each of its divisors present in $A$.
|
|
|
|
An easy solution is that in code, a hashmap could track the number of times each number is counted, and iteratively remove duplicates.
|
|
|
|
The goal is to not add the number if it was already added.
|
|
|
|
Mathamatically this can be done piecewise. If a previous element of $A$ divides $A_i k$, skip that number.
|
|
|
|
#text(fill: white, html.frame(
|
|
$
|
|
f(A, L) = sum_(i)^abs(A)[sum_(k=1)^floor((L-1)/A_i) cases(0 quad & A_j divides A_i k and j < k, A_i k quad & A_j divides.not A_i k and j < k)]
|
|
$
|
|
)) |