Commit bd756ea1 authored by Nayuki Minase's avatar Nayuki Minase

P89, P91, P92, P97, P102, P104, P112, P113, P114, P115, P116, P117, P218: Added Python solutions.

parent 87dee051
......@@ -88,6 +88,19 @@ ANSWERS = {
80: "40886",
81: "427337",
85: "2772",
89: "743",
91: "14234",
92: "8581146",
97: "8739992577",
102: "228",
104: "329468",
112: "1587000",
113: "51161058134250",
114: "16475640049",
115: "168",
116: "20492570929",
117: "100808458960497",
218: "0",
}
......
This diff is collapsed.
#
# Solution to Project Euler problem 91
# by Project Nayuki
#
# http://www.nayuki.io/page/project-euler-solutions
# https://github.com/nayuki/Project-Euler-solutions
#
def compute():
LIMIT = 51
ans = 0
for x1 in range(LIMIT):
for y1 in range(LIMIT):
for x2 in range(LIMIT):
for y2 in range(LIMIT):
# For uniqueness, ensure that (x1,y1) has a larger angle than (x2,y2)
if y2 * x1 < y1 * x2 and is_right_triangle(x1, y1, x2, y2):
ans += 1
return str(ans)
# Tests whether {(0,0), (x1,y1), (x2,y2)} forms a right triangle.
def is_right_triangle(x1, y1, x2, y2):
dx = x2 - x1
dy = y2 - y1
a = x1 * x1 + y1 * y1
b = x2 * x2 + y2 * y2
c = dx * dx + dy * dy
return a + b == c or b + c == a or c + a == b
if __name__ == "__main__":
print(compute())
#
# Solution to Project Euler problem 92
# by Project Nayuki
#
# http://www.nayuki.io/page/project-euler-solutions
# https://github.com/nayuki/Project-Euler-solutions
#
def compute():
ans = 0
for i in range(1, 10000000):
while i != 1 and i != 89:
i = square_digit_sum(i)
if i == 89:
ans += 1
return str(ans)
def square_digit_sum(n):
result = 0
while n > 0:
x = n % 10
result += x * x
n //= 10
return result
if __name__ == "__main__":
print(compute())
#
# Solution to Project Euler problem 97
# by Project Nayuki
#
# http://www.nayuki.io/page/project-euler-solutions
# https://github.com/nayuki/Project-Euler-solutions
#
def compute():
MOD = 10**10
ans = (28433 * pow(2, 7830457, MOD) + 1) % MOD
return str(ans)
if __name__ == "__main__":
print(compute())
This diff is collapsed.
#
# Solution to Project Euler problem 104
# by Project Nayuki
#
# http://www.nayuki.io/page/project-euler-solutions
# https://github.com/nayuki/Project-Euler-solutions
#
def compute():
MOD = 10**9
a = 0
b = 1
i = 0
while True:
if "".join(sorted(str(a))) == "123456789" and "".join(sorted(str(fibonacci(i)[0])[ : 9])) == "123456789":
return str(i)
a, b = b, (a + b) % MOD
i += 1
return str(ans)
# Returns the tuple (F(n), F(n+1)).
def fibonacci(n):
if n == 0:
return (0, 1)
else:
a, b = fibonacci(n // 2)
c = a * (b * 2 - a)
d = a * a + b * b
if n % 2 == 0:
return (c, d)
else:
return (d, c + d)
if __name__ == "__main__":
print(compute())
#
# Solution to Project Euler problem 112
# by Project Nayuki
#
# http://www.nayuki.io/page/project-euler-solutions
# https://github.com/nayuki/Project-Euler-solutions
#
import itertools
def compute():
count = 0
for i in itertools.count(1):
s = str(i)
t = "".join(sorted(s))
if s != t and s[::-1] != t:
count += 1 # i is bouncy
if count * 100 == 99 * i:
return str(i)
if __name__ == "__main__":
print(compute())
#
# Solution to Project Euler problem 113
# by Project Nayuki
#
# http://www.nayuki.io/page/project-euler-solutions
# https://github.com/nayuki/Project-Euler-solutions
#
import eulerlib
# Let n be the number of digits. To count the number of increasing or decreasing numbers using combinatorics,
# let's view each number as a sequence of digit readout slots and operations. For example, suppose n=5 and
# we examine the increasing number 23667. We can express it as the sequence "+ + # + # + + + # # + # + +",
# where # is a digit and + means increment. This way of thinking will be useful, as we will see.
#
# For the set of increasing numbers, each number has n readout slots and 9 increments, positioned arbitrarily.
# Using this construction, the number is guaranteed to be increasing. Note that leading zeros can be produced.
# Conversely, for each increasing number, we can generate a (unique) sequence of slots and increments that represents it
# (putting all unused increments after the rightmost digit). Hence there are n+9 objects to arrange in sequence,
# so there are binomial(n + 9, 9) ways to arrange them. Finally we subtract 1 because 0 can be formed with this scheme,
# which must be excluded from the set of increasing numbers.
#
# For the set of decreasing numbers, each number has n readout slots and 10 operations. Of the 10 operations,
# the leading one must be "increment to 9", and the rest must be decrements. Similar to the increasing case,
# each sequence of slots and decrements produces a decreasing number, and conversely each decreasing number
# corresponds to a unique sequence of slots and decrements. However, 0 can be formed in n+1 ways, by concentrating
# all 10 operations between some pair of slots, e.g. "+9 -9 # # # #", "# +9 -9 # # #", ..., "# # # # +9 -9".
#
# There are 9n "flat" numbers, for example: 1, 2, ..., 9; 11, 22, ..., 99; 111, 222, ..., 999; ... (note that 0 is excluded).
# Since they are double-counted in the increasing and decreasing numbers, we subtract the size of this set.
#
# In conclusion, the number of non-bouncy numbers is (binomial(n+9,9) - 1) + (binomial(n+10,10) - (n+1)) - 9n.
#
# (Technically, in the problem statement and this solution, "increasing" actually means "nondecreasing" and "decreasing" means "nonincreasing".)
def compute():
DIGITS = 100
increasing = binomial(DIGITS + 9, 9) - 1
decreasing = binomial(DIGITS + 10, 10) - (DIGITS + 1)
flat = DIGITS * 9
ans = increasing + decreasing - flat
return str(ans)
def binomial(n, k):
return eulerlib.factorial(n) // (eulerlib.factorial(k) * eulerlib.factorial(n - k))
if __name__ == "__main__":
print(compute())
#
# Solution to Project Euler problem 114
# by Project Nayuki
#
# http://www.nayuki.io/page/project-euler-solutions
# https://github.com/nayuki/Project-Euler-solutions
#
# How many ways can a row n units long be filled? Denote this quantity as ways[n].
# Compute n = 0, 1, 2 manually as base cases.
#
# Now assume n >= 3. Look at the leftmost item and sum up the possibilities.
# - If the item is a black square, then the rest of the row is allowed
# to be anything of length n-1. Add ways[n-1].
# - If the item is a red block with length k where k >= 3, then:
# - If k = n, then the whole row is filled by this red block. Add 1.
# - Otherwise k < n, this red block is followed by a black square, then followed
# by anything of length n-k-1. So add ways[n-4] + ways[n-5] + ... + ways[0].
def compute():
# Dynamic programming
LENGTH = 50
ways = [0] * (LENGTH + 1)
for n in range(len(ways)):
if n < 3:
ways[n] = 1
else:
ways[n] = ways[n - 1] + sum(ways[ : n - 3]) + 1
return str(ways[-1])
if __name__ == "__main__":
print(compute())
#
# Solution to Project Euler problem 115
# by Project Nayuki
#
# http://www.nayuki.io/page/project-euler-solutions
# https://github.com/nayuki/Project-Euler-solutions
#
import itertools
# How many ways can a row n units long be filled, where red blocks are
# at least m units long? Denote this quantity as ways[n].
# Compute n = 0 manually as a base case.
#
# Now assume n >= 1. Look at the leftmost item and sum up the possibilities.
# - If the item is a black square, then the rest of the row is allowed
# to be anything of length n-1. Add ways[n-1].
# - If the item is a red block with length k where k >= m, then:
# - If k = n, then the whole row is filled by this red block. Add 1.
# - Otherwise k < n, this red block is followed by a black square, then followed
# by anything of length n-k-1. So add ways[n-m-1] + ways[n-m-2] + ... + ways[0].
def compute():
# Dynamic programming
M = 50
ways = [1]
for n in itertools.count(1):
s = ways[n - 1] + sum(ways[ : max(n - M, 0)])
if n >= M:
s += 1
ways.append(s)
if s > 1000000:
return str(n)
if __name__ == "__main__":
print(compute())
#
# Solution to Project Euler problem 116
# by Project Nayuki
#
# http://www.nayuki.io/page/project-euler-solutions
# https://github.com/nayuki/Project-Euler-solutions
#
def compute():
LENGTH = 50
return str(sum(count_ways(LENGTH, i) for i in range(2, 5)))
# How many ways can a row n units long be filled with black squares 1 unit long
# and colored tiles m units long? Denote this quantity as ways[n].
# Compute n = 0 manually as a base case.
#
# Now assume n >= 1. Look at the leftmost item and sum up the possibilities.
# - If the item is a black square, then the rest of the row
# is allowed to be anything of length n-1. Add ways[n-1].
# - If the item is a colored tile of length m where m <= n, then the
# rest of the row can be anything of length n-m. Add ways[n-m].
#
# At the end, return ways[length]-1 to exclude the case where the row is all black squares.
def count_ways(length, m):
# Dynamic programming
ways = [0] * (length + 1)
ways[0] = 1
for n in range(1, len(ways)):
ways[n] += ways[n - 1]
if n >= m:
ways[n] += ways[n - m]
return ways[-1] - 1
if __name__ == "__main__":
print(compute())
#
# Solution to Project Euler problem 117
# by Project Nayuki
#
# http://www.nayuki.io/page/project-euler-solutions
# https://github.com/nayuki/Project-Euler-solutions
#
# How many ways can a row n units long be filled with:
# - Black squares 1 unit long
# - Red tiles 2 units long
# - Green tiles 3 units long
# - Blue tiles 4 units long
# Denote this quantity as ways[n].
#
# Compute n = 0 manually as a base case.
# Now assume n >= 1. Look at the leftmost item and sum up the possibilities.
# - Black square (n>=1): Rest of the row can be anything of length n-1. Add ways[n-1].
# - Red tile (n>=2): Rest of the row can be anything of length n-2. Add ways[n-2].
# - Green tile (n>=3): Rest of the row can be anything of length n-3. Add ways[n-3].
# - Blue tile (n>=4): Rest of the row can be anything of length n-4. Add ways[n-4].
def compute():
# Dynamic programming
LENGTH = 50
ways = [0] * (LENGTH + 1)
ways[0] = 1
for n in range(1, len(ways)):
ways[n] += sum(ways[max(n - 4, 0) : n])
return str(ways[-1])
if __name__ == "__main__":
print(compute())
#
# Solution to Project Euler problem 218
# by Project Nayuki
#
# http://www.nayuki.io/page/project-euler-solutions
# https://github.com/nayuki/Project-Euler-solutions
#
# == Primitive Pythagorean triples ==
#
# Each valid pair generates a PPT:
#
# For each pair of positive integers (s,t) such that s > t, they are coprime, and one of them
# is odd and one of them is even: Let a = s^2 - t^2 (odd), b = 2st (even), and c = s^2 + t^2 (odd).
# Then (a,b,c) is a primitive Pythagorean triple (PPT).
#
# Proof: The fact that a^2 + b^2 = c^2 can be readily verified. Now for the sake of contradiction,
# suppose some prime p divides each of {a,b,c} (which would make the Pythagorean triple non-primitive).
# Since p divides b = 2st and p is prime, p must divide at least one of {2,s,t}. a is odd, so 2 doesn't
# divide a, so p != 2. Hence p > 2, and p must divide at least one of {s,t}. p divides c = s^2 + t^2.
# WLOG if p divides s, then p divides the difference c - s^2 = t^2, thus p divides t.
# Therefore p divides {s,t}, contradicting that {s,t} are coprime.
#
# Each PPT can be generated from some valid pair:
#
# Conversely, for each PPT (a,b,c) there exists an (s,t), satisfying the restrictions above,
# that generates it using the relations above.
#
# Proof: WLOG assume that a is odd (otherwise swap the roles of a and b). Knowing that a^2 + b^2 = c^2
# and b is even, rearrange it to get (b/2)^2 = (c^2 - a^2)/4 = [(c-a)/2][(c+a)/2]. The claim is that
# (c-a)/2 and (c+a)/2 are both perfect squares. For any prime p, if it divides both (c-a)/2 and (c+a)/2,
# then it divides the sum (which is c) and the difference (which is a), so it would also divide c^2 - a^2 = b^2,
# contradicting the primitiveness. Thus each prime power (i.e. p^k) in the factorization of (b/2)^2 appears
# in either the factor (c-a)/2 or the factor (c+a)/2. Since (b/2)^2 is a perfect square, each prime power
# in it is a perfect square, and it would contribute to either (c-a)/2 or (c+a)/2, making both of them
# perfect squares as well.
#
# With this setup, let s = sqrt((c+a)/2) and t = sqrt((c-a)/2), which are both positive integers.
# It's easy to verify that a = s^2 - t^2, b = 2st, and c = s^2 + t^2. Clearly s > t, since a is added in s
# while a is subtracted in t. {s,t} cannot both be even or both be odd, otherwise 2 divides all of {a,b,c},
# contradicting primitiveness. {s,t} must be coprime, otherwise some p divides {s,t}, so p^2 divides s^2 = (c+a)/2
# and p^2 divides t^2 = (c-a)^2, which contradicts {a,c} being coprime using the argument above.
#
#
# == Perfect triangles ==
#
# A perfect right-angled triangle (a,b,c) has c = r^2 for some integer r. We use the PPT theorem converse
# to find (s,t). The area of the triangle (a,b,c) is ab/2 = (s^2 - t^2)(2st)/2 = st(s^2 - t^2).
# Curiously, we have c = s^2 + t^2 = r^2, which means (s,t,r) is itself a Pythagorean triple, and in fact
# a primitive one because (s,t) are coprime. Use the PPT theorem converse on (s,t,r) (or (t,s,r), depending on
# which of s or t is odd) to find (u,v), i.e. s = u^2 - v^2, t = 2uv, and r = u^2 + v^2.
# So the area is also expressible as (u^2 - v^2)(2uv)[(u^2 - v^2)^2 - (2uv)^2].
#
# The area is divisible by 6 and 28 (super-perfectness) iff it is divisible by lcm(6, 28) = 84
# = 3 * 4 * 7 (coprime factorization) iff it is divisible by 3, 4, and 7.
# Now, the area is divisible by 4 because in the factor 2uv, either u or v is even.
# The area is divisible by 3 because st is a factor in one of the area formulas, and with (s,t,r) being
# a Pythagorean triple, at least one of {s,t} must be 0 mod 3 (see footnote 0).
# Similarly, since (s,t,r) is a Pythagorean triple, 7 divides at least one of {s,t} (so 7 divides
# the area factor of st), or s^2 = t^2 mod 7 (so 7 divides the area factor s^2 - t^2) (see footnote 1).
#
# In conclusion, every perfect right-angled triangle is also super-perfect.
# There is no perfect triangle that isn't super-perfect.
#
# Footnote 0: This can be proven by brute force over the 3^3 cases of values of s,t,r mod 3.
# Or alternatively: If s or t is 0 mod 3, then we're done. Otherwise, s is either 1 or 2 mod 3,
# and t is either 1 or 2 mod 3. s^2 = 1 mod 3, and t^2 = 1 mod 3. s^2 + t^2 = 2 = r^2 mod 3,
# but no r can satisfy r^2 = 2 mod 3. So this "otherwise" case is impossible.
#
# Footnote 1: This can also be proven by brute force over all 7^3 cases of values of s,t,r mod 7.
# Or alternatively: If s or t is 0 mod 7, then we're done. Otherwise, notice that for k != 0 mod 7,
# we have that k^2 mod 7 is in the set {1,2,4} (quadratic residues). If s^2 != t^2 mod 7,
# then their sum mod 7 is not a residue, so r^2 != s^2 + t^2. Therefore it must be that s^2 = t^2 mod 7
# (e.g. s = 3 mod 7, t = 4, r = 2 mod 7).
def compute():
return "0"
if __name__ == "__main__":
print(compute())
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment