Skip to content

Commit 79da386

Browse files
authored
Pe381 (#126)
* improving new_problem * add solution for pe381
1 parent f1dcc58 commit 79da386

File tree

2 files changed

+160
-4
lines changed

2 files changed

+160
-4
lines changed

solutions/PE381.py

Lines changed: 101 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,101 @@
1+
"""
2+
PROBLEM
3+
4+
For a prime p let S(p) = (sum (p-k)!) mod p for 1 <= k <= 5.
5+
6+
For example, if p=7,
7+
8+
(7-1)! + (7-2)! + (7-3)! + (7-4)! + (7-5)! = 6! + 5! + 4! + 3! + 2! = 720+120+24+6+2 = 872.
9+
10+
As 872 mod (7) = 4, S(7) = 4.
11+
12+
It can be verified that sum S(p) = 480 for 5 <= p < 100.
13+
14+
Find sum S(p) for 5 <= p < 10^8.
15+
16+
ANSWER: 139602943319822
17+
Solve time: 3.661 seconds
18+
"""
19+
20+
import unittest
21+
from util.utils import timeit, primes_upto
22+
23+
24+
# with Wilson's theorem, we know that (p-1)! = -1 mod p
25+
# so we can rewrite the sum as:
26+
# S(p) = (\sum_{k=1}^{5} (p-k)!) mod p
27+
28+
# (p-1)! = -1 mod p
29+
# (p-2)! = -1/(p-1) = -1/(-1) = 1 mod p
30+
# (p-3)! = 1/(p-2) = 1/(-2) = -1/2 mod p
31+
# (p-4)! = (-1/2)/(p-3) = (-1/2)/(-3) = 1/6 mod p
32+
# (p-5)! = (1/6)/(p-4) = (1/6)/(-4) = -1/24 mod p
33+
# so S(p) = (-1 + 1 - 1/2 + 1/6 - 1/24) mod p = (-12 + 4 - 1)/24 = -9/24 = -3/8 mod p
34+
35+
# 1/(p-1) mod p = x such that x * (p-1) = 1 mod p
36+
# x * (-1) = 1 mod p
37+
# x = -1 mod p
38+
39+
# 1/(p-2) mod p = x such that x * (p-2) = 1 mod p
40+
# x * (-2) = 1 mod p
41+
# x = -1/2 mod p
42+
43+
# 1/(p-3) mod p = x such that x * (p-3) = 1 mod p
44+
# x * (-3) = 1 mod p
45+
# x = -1/3 mod p
46+
47+
# 1/(p-4) mod p = x such that x * (p-4) = 1 mod p
48+
# x * (-4) = 1 mod p
49+
# x = -1/4 mod p
50+
51+
# 1/(p-5) mod p = x such that x * (p-5) = 1 mod p
52+
# x * (-5) = 1 mod p
53+
# x = -1/5 mod p
54+
55+
# We need to find the sum of S(p) for all primes 5 <= p < N
56+
# S(p) = -3/8 mod p
57+
58+
# example N = 100
59+
# S(5) = -3/8 mod 5 = -3 * 2 mod 5 = -6 mod 5 = 4
60+
# S(7) = -3/8 mod 7 = -3 * 6 mod 7 = -18 mod 7 = 4
61+
# S(11) = -3/8 mod 11 = -3 * 7 mod 11 = -21 mod 11 = 1
62+
# S(13) = -3/8 mod 13 = -3 * 5 mod 13 = -15 mod 13 = 11
63+
# S(17) = -3/8 mod 17 = -3 * 15 mod 17 = -45 mod 17 = 11
64+
# S(19) = -3/8 mod 19 = -3 * 12 mod 19 = -36 mod 19 = 2
65+
# S(23) = -3/8 mod 23 = -3 * 14 mod 23 = -42 mod 23 = 4
66+
# S(29) = -3/8 mod 29 = -3 * 11 mod 29 = -33 mod 29 = 26
67+
# S(31) = -3/8 mod 31 = -3 * 27 mod 31 = -81 mod 31 = 13
68+
# S(37) = -3/8 mod 37 = -3 * 28 mod 37 = -84 mod 37 = 9
69+
70+
71+
72+
class Problem381:
73+
def __init__(self):
74+
pass
75+
76+
@timeit
77+
def solve(self, n):
78+
primes = primes_upto(n)
79+
total = 0
80+
for p in primes[2:]:
81+
total += self.S(int(p))
82+
return total
83+
84+
@staticmethod
85+
def S(p):
86+
return (pow(-8, -1, p) * 3) % p
87+
88+
89+
class Solution381(unittest.TestCase):
90+
def setUp(self):
91+
self.problem = Problem381()
92+
93+
def test_small_n(self):
94+
self.assertEqual(480, self.problem.solve(n=100))
95+
96+
def test_solution(self):
97+
self.assertEqual(139602943319822, self.problem.solve(n=int(pow(10, 8))))
98+
99+
100+
if __name__ == '__main__':
101+
unittest.main()

solutions/new_problem.py

Lines changed: 59 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,60 @@
11
import os
22
import argparse
33
import sys
4+
import requests
5+
from bs4 import BeautifulSoup
6+
7+
def get_problem_description(n):
8+
url = f"https://projecteuler.net/problem={n}"
9+
headers = {
10+
'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36'
11+
}
12+
try:
13+
response = requests.get(url, headers=headers, timeout=10)
14+
if response.status_code == 200:
15+
soup = BeautifulSoup(response.content, 'html.parser')
16+
problem_content = soup.find('div', class_='problem_content')
17+
if problem_content:
18+
# Remove script and style tags
19+
for script in problem_content(["script", "style"]):
20+
script.decompose()
21+
22+
# Replace <br> with newlines
23+
for br in problem_content.find_all('br'):
24+
br.replace_with('\n')
25+
26+
# Replace <p> with newlines around content
27+
for p in problem_content.find_all('p'):
28+
p.insert_before('\n')
29+
p.insert_after('\n')
30+
31+
# Extract text
32+
text = problem_content.get_text()
33+
34+
# Clean up multiple newlines and spaces
35+
lines = [line.strip() for line in text.split('\n')]
36+
# Filter out multiple consecutive empty lines
37+
cleaned_lines = []
38+
for line in lines:
39+
if line or (cleaned_lines and cleaned_lines[-1] != ''):
40+
cleaned_lines.append(line)
41+
42+
return '\n'.join(cleaned_lines).strip()
43+
except Exception as e:
44+
print(f"Warning: Could not fetch problem description: {e}")
45+
return "PROBLEM DESCRIPTION COULD NOT BE AUTOMATICALLY RETRIEVED."
46+
47+
TEMPLATE = """r\"\"\"
48+
PROBLEM
49+
50+
{1}
51+
52+
ANSWER:
53+
Solve time:
54+
\"\"\"
455
5-
TEMPLATE = """from util.utils import timeit
656
import unittest
57+
from util.utils import timeit
758
859
960
class Problem{0}:
@@ -26,7 +77,6 @@ def test_solution(self):
2677
2778
if __name__ == '__main__':
2879
unittest.main()
29-
3080
"""
3181

3282
if __name__ == '__main__':
@@ -42,7 +92,12 @@ def test_solution(self):
4292
if os.path.exists(f'./{fn}'):
4393
raise AssertionError(
4494
f'{fn} already exists! Just update the file you lazy bastard!')
45-
with open(fn, 'w') as f:
46-
f.write(TEMPLATE.format(args.p))
95+
96+
print(f"Fetching problem {args.p} description...")
97+
description = get_problem_description(args.p)
98+
99+
with open(fn, 'w', encoding='utf-8') as f:
100+
f.write(TEMPLATE.format(args.p, description))
47101

102+
print(f"Created {fn} with problem description.")
48103
sys.exit(0)

0 commit comments

Comments
 (0)