From c5622fc96881f2a0f2e98b32cc8a8ce801e5b269 Mon Sep 17 00:00:00 2001 From: filifa Date: Sat, 24 May 2025 23:34:48 -0400 Subject: [PATCH] show the easy way with SageMath --- notebooks/problem0031.ipynb | 53 ++++++++++++++++++++++++++++--------- notebooks/problem0077.ipynb | 42 ++++++++++++++++++++++++++--- 2 files changed, 80 insertions(+), 15 deletions(-) diff --git a/notebooks/problem0031.ipynb b/notebooks/problem0031.ipynb index 167f909..c3fedc8 100644 --- a/notebooks/problem0031.ipynb +++ b/notebooks/problem0031.ipynb @@ -1,13 +1,42 @@ { "cells": [ + { + "cell_type": "markdown", + "id": "e5793a3a", + "metadata": {}, + "source": [ + "# [Coin Sums](https://projecteuler.net/problem=31)\n", + "\n", + "The easiest thing to do here is... let SageMath do the whole thing for us." + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "9bedec84", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "73682" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "Partitions(200, parts_in=(1,2,5,10,20,50,100,200)).cardinality()" + ] + }, { "cell_type": "markdown", "id": "44f7d7da", "metadata": {}, "source": [ - "# [Coin Sums](https://projecteuler.net/problem=31)\n", - "\n", - "There's a *very* cool way to solve this problem using [generating functions](https://en.wikipedia.org/wiki/Generating_function).\n", + "But that's boring, and there's a *very* cool way to solve this problem using [generating functions](https://en.wikipedia.org/wiki/Generating_function).\n", "\n", "## Generating functions\n", "If you're not familiar, a generating function is a way of expressing a sequence as coefficients of a [formal power series](https://en.wikipedia.org/wiki/Formal_power_series). For example, the generating function for the Fibonacci sequence is\n", @@ -24,7 +53,7 @@ "\n", "Similarly, how many ways can you make 0 cents, 1 cent, 2 cents, etc. using only 2 cent coins? Answer: every even value has one way of making change, and every odd value has zero ways (1, 0, 1, 0, 1, 0, ...). Similarly, with only 5 cent coins, there is one way to make change for every multiple of 5, and zero ways for every other value (1, 0, 0, 0, 0, 1, ...).\n", "\n", - "We can express the solutions to each of these questions as sequences, and therefore as generating functions:\n", + "We can express the answers to each of these questions as sequences, and therefore as generating functions:\n", "$$\\begin{align}\n", "1 + x + x^2 + x^3 + \\cdots = \\frac{1}{1-x}\\\\\n", "1 + x^2 + x^4 + x^6 + \\cdots = \\frac{1}{1-x^2}\\\\\n", @@ -47,7 +76,7 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 2, "id": "74c5fe00", "metadata": {}, "outputs": [ @@ -57,7 +86,7 @@ "x^18 + x^17 + 2*x^16 + 2*x^15 + 3*x^14 + 4*x^13 + 5*x^12 + 6*x^11 + 5*x^10 + 6*x^9 + 5*x^8 + 6*x^7 + 5*x^6 + 4*x^5 + 3*x^4 + 2*x^3 + 2*x^2 + x + 1" ] }, - "execution_count": 1, + "execution_count": 2, "metadata": {}, "output_type": "execute_result" } @@ -106,7 +135,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 3, "id": "c351c248", "metadata": {}, "outputs": [ @@ -116,7 +145,7 @@ "73682.0" ] }, - "execution_count": 2, + "execution_count": 3, "metadata": {}, "output_type": "execute_result" } @@ -149,7 +178,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 4, "id": "33bbc1a4", "metadata": {}, "outputs": [ @@ -159,7 +188,7 @@ "73682" ] }, - "execution_count": 3, + "execution_count": 4, "metadata": {}, "output_type": "execute_result" } @@ -179,7 +208,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 5, "id": "c2a5db7e", "metadata": {}, "outputs": [ @@ -189,7 +218,7 @@ "73682" ] }, - "execution_count": 4, + "execution_count": 5, "metadata": {}, "output_type": "execute_result" } diff --git a/notebooks/problem0077.ipynb b/notebooks/problem0077.ipynb index b820bb6..58fe42a 100644 --- a/notebooks/problem0077.ipynb +++ b/notebooks/problem0077.ipynb @@ -7,12 +7,48 @@ "source": [ "# [Prime Summations](https://projecteuler.net/problem=77)\n", "\n", - "Once again, we can adapt our solution to [problem 31](https://projecteuler.net/problem=31). Here, there's the added wrinkle that we don't know how far out we need to calculate our generating function, but we can work around this by just repeatedly increasing our precision and recalculating until we find our answer." + "We can once again adapt any of our methods from [problem 31](https://projecteuler.net/problem=31), including the easiest one: just let SageMath figure it out." ] }, { "cell_type": "code", "execution_count": 1, + "id": "4c066047", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "71" + ] + }, + "execution_count": 1, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "from itertools import count\n", + "\n", + "for n in count(1):\n", + " p = Partitions(n, parts_in=prime_range(n)).cardinality()\n", + " if p > 5000:\n", + " break\n", + " \n", + "n" + ] + }, + { + "cell_type": "markdown", + "id": "cd20554a", + "metadata": {}, + "source": [ + "Somewhat more interestingly, we could use generating functions again. This time, there's the added wrinkle that we don't know how far out we need to calculate our generating function, but we can work around this by just repeatedly increasing our precision and recalculating until we find our answer." + ] + }, + { + "cell_type": "code", + "execution_count": 2, "id": "1b5376e2", "metadata": {}, "outputs": [ @@ -22,7 +58,7 @@ "1 + x^2 + x^3 + x^4 + 2*x^5 + 2*x^6 + 3*x^7 + 3*x^8 + 4*x^9 + 5*x^10 + 6*x^11 + 7*x^12 + 9*x^13 + 10*x^14 + 12*x^15 + 14*x^16 + 17*x^17 + 19*x^18 + 23*x^19 + 26*x^20 + 30*x^21 + 35*x^22 + 40*x^23 + 46*x^24 + 52*x^25 + 60*x^26 + 67*x^27 + 77*x^28 + 87*x^29 + 98*x^30 + 111*x^31 + 124*x^32 + 140*x^33 + 157*x^34 + 175*x^35 + 197*x^36 + 219*x^37 + 244*x^38 + 272*x^39 + 302*x^40 + 336*x^41 + 372*x^42 + 413*x^43 + 456*x^44 + 504*x^45 + 557*x^46 + 614*x^47 + 677*x^48 + 744*x^49 + 819*x^50 + 899*x^51 + 987*x^52 + 1083*x^53 + 1186*x^54 + 1298*x^55 + 1420*x^56 + 1552*x^57 + 1695*x^58 + 1850*x^59 + 2018*x^60 + 2198*x^61 + 2394*x^62 + 2605*x^63 + 2833*x^64 + 3079*x^65 + 3344*x^66 + 3630*x^67 + 3936*x^68 + 4268*x^69 + 4624*x^70 + 5007*x^71 + 5419*x^72 + 5861*x^73 + 6336*x^74 + 6845*x^75 + 7393*x^76 + 7979*x^77 + 8608*x^78 + 9282*x^79 + O(x^80)" ] }, - "execution_count": 1, + "execution_count": 2, "metadata": {}, "output_type": "execute_result" } @@ -31,7 +67,7 @@ "prec = 20\n", "while True:\n", " R. = PowerSeriesRing(ZZ, default_prec=prec)\n", - " G = 1 / prod(1 - x^p for p in primes_first_n(prec))\n", + " G = 1 / prod(1 - x^p for p in prime_range(prec))\n", " \n", " d = G.dict()\n", " if any(c > 5000 for c in d.values()):\n",