Teaser 2841: Crenellation aggregation
From The Sunday Times, 5th March 2017 [link] [link]
The castle’s crenellated outer walls formed a pentagon, and on a family visit we decided to count the crenels. My son counted the number on each side and found that these totals on each side were five consecutive two figure numbers. My daughter and wife started together and then one of them walked clockwise around the walls and the other walked anticlockwise. They each counted the crenels they passed until they met. Their totals were two different prime numbers (with no prime number between the two). I consulted the tourist leaflet and found that the total number of crenels was in fact the product of three prime numbers.
How many crenels were there in total?
[teaser2841]
Jim Randell 8:43 am on 2 December 2021 Permalink |
We can express the the total number of crenels in three different ways (assuming no mistakes were made in the counting):
This Python program looks at consecutive primes, until it finds a total that satisfies the remaining two expressions.
It runs in 47ms.
Run: [ @replit ]
from enigma import (primes, tuples, div, printf) # consider consecutive pairs of primes (primes.between(29, 242) is sufficient) for (p1, p2) in tuples(primes.between(2, 485), 2): # form the total t = p1 + p2 if t < 60: continue if t > 485: break # check it can be expressed as 5n + 10 n = div(t - 10, 5) if n is None: continue # check it is the product of three prime numbers qs = primes.factor(t) if len(qs) != 3: continue # output solution printf("{t} = +({n}..{n4}) = {p1} + {p2} = *{qs}", n4=n + 4)Solution: There were 410 crenels in total.
So we have:
LikeLike
Frits 10:59 pm on 2 December 2021 Permalink |
More analysis and using the 6n + 1 or 6n – 1 rule (just for fun).
Other than 2 and 3, prime numbers must be of the form 6n + 1 or 6n – 1.
Enigma function is_prime() is called only once.
Function islice() is borrowed from enigma function first().
from itertools import islice from enigma import is_prime # t = 5n + 10 (where 10 <= n <= 95, so 60 <= t <= 485) # t = p1 + p2 (where p1 and p2 are consecutive primes) ==> t is even # t = q1 × q2 × q3 (where q1, q2, q3 are primes and q1 <= q2 <= q3) # t is even ==> q1 = 2, n is even and 30 <= q2 x q3 <= 242 # n is even ==> n = 2 * m and 5 <= m <= 47 # t = p1 + p2 = 2 * (q2 * q3) = 10m + 10 = (m + 1) * 10 # t must end on a zero ==> q2 must be 5 and 6 <= q3 <= 48 # t = 10 * q3 ==> q3 = m + 1 # list of prime numbers from 6 up to 48 (used for q3) P = {3, 5, 7} P |= {x for x in range(11, 49, 2) if all(x % p for p in P)} P = {x for x in P if x > 5} # try to express next prime as 6k - 1 or 6k + 1 def nextprime(n): # in this puzzle n always ends on a 5 return list(islice([p for x in range(n // 6 + 1, 81) for i in [-1, 1] if is_prime(p := 6 * x + i) and p > n], 0, 1))[0] # list of prime numbers from 31 (prime before 5 x 7) up to 235 (5 x 47) P2 = {3, 5, 7, 11, 13, 17} P2 |= {x for x in range(19, 236, 2) if all(x % p for p in P2)} # try to express previous prime as 6k - 1 or 6k + 1 def prevprime(n): # in this puzzle n always ends on a 5 return list(islice([p for x in range(n // 6, 0, -1) for i in [1, -1] if (p := 6 * x + i) in P2 and p < n], 0, 1))[0] bef35 = prevprime(35) # prime number before 5 x lowest q3 prime P2 = {x for x in P2 if x >= bef35} # add one more prime (to be found by nextprime_P2() ) np = nextprime(max(P2)) P2.add(np) P2limit = np // 6 + 1 # variable to be used in nextprime_P2() # try to express next prime as 6k - 1 or 6k + 1 def nextprime_P2(n): # in this puzzle n always ends on a 5 return list(islice([p for x in range(n // 6 + 1, P2limit) for i in [-1, 1] if (p := 6 * x + i) in P2 and p > n], 0, 1))[0] # t = q1 x q2 x q3 = 2 x 5 x q3 for q3 in P: t = 10 * q3 # find prime before half of t p1 = prevprime(5 * q3) # t = p1 + p2 (where p1 and p2 are consecutive primes) if t - p1 not in P2: continue if nextprime_P2(5 * q3) != t - p1: continue print(t, "crenels in total")LikeLike
Jim Randell 4:30 pm on 3 December 2021 Permalink |
I’m considering adding [[
Primes.before(n)]] and [[Primes.after()]] to the prime sieve class, which would give you the largest prime less than n and the smallest prime greater than n.[Note: These routines are now available in enigma.py]
The puzzle could then be solved with:
Run: [ @replit ]
from enigma import (primes, printf) primes.expand(252) for q in primes.between(6, 48): m = 5 * q p1 = primes.before(m) p2 = primes.after(m) t = 2 * m if p1 + p2 == t: n = 2 * q - 2 # output solution printf("t={t} = +({p1}, {p2}) = *(2, 5, {q}) = +({n}..{n4})", n4=n + 4)LikeLike