Files
site/static/posts/pe-p1/post.typ
T
jjanella c41ae4da75
Build / build (push) Failing after 14m29s
fix-math
2026-07-29 18:15:35 -04:00

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:
#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$:
#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.
#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)]
$
)