-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathp064.py
90 lines (65 loc) · 1.75 KB
/
p064.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
#
# Solution to Project Euler problem 64
import eulerlib, fractions
def compute():
ans = sum(1 for i in range(1, 10001) if (not eulerlib.is_square(i) and get_sqrt_continued_fraction_period(i) % 2 == 1))
return str(ans)
# Returns the period of the continued fraction of sqrt(n)
def get_sqrt_continued_fraction_period(n):
seen = {}
val = QuadraticSurd(0, 1, 1, n)
while True:
seen[val] = len(seen)
val = (val - QuadraticSurd(val.floor(), 0, 1, val.d)).reciprocal()
if val in seen:
return len(seen) - seen[val]
# Represents (a + b * sqrt(d)) / c. d must not be a perfect square.
class QuadraticSurd(object):
def __init__(self, a, b, c, d):
if c == 0:
raise ValueError()
# Simplify
if c < 0:
a = -a
b = -b
c = -c
gcd = fractions.gcd(fractions.gcd(a, b), c)
if gcd != 1:
a //= gcd
b //= gcd
c //= gcd
self.a = a
self.b = b
self.c = c
self.d = d
def __sub__(self, other):
if self.d != other.d:
raise ValueError()
return QuadraticSurd(
self.a * other.c - other.a * self.c,
self.b * other.c - other.b * self.c,
self.c * other.c,
self.d)
def reciprocal(self):
return QuadraticSurd(
-self.a * self.c,
self.b * self.c,
self.b * self.b * self.d - self.a * self.a,
self.d)
def floor(self):
temp = eulerlib.sqrt(self.b * self.b * self.d)
if self.b < 0:
temp = -(temp + 1)
temp += self.a
if temp < 0:
temp -= self.c - 1
return temp // self.c
def __eq__(self, other):
return self.a == other.a and self.b == other.b \
and self.c == other.c and self.d == other.d
def __ne__(self, other):
return not (self == other)
def __hash__(self):
return hash(self.a) + hash(self.b) + hash(self.c) + hash(self.d)
if __name__ == "__main__":
print(compute())