Skip to content

Commit a2c6f49

Browse files
committed
add solution to pe169
1 parent 6f5a72d commit a2c6f49

File tree

1 file changed

+76
-0
lines changed

1 file changed

+76
-0
lines changed

solutions/PE169.py

Lines changed: 76 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,76 @@
1+
"""
2+
PROBLEM
3+
4+
Define f(0) = 1 and f(n) to be the number of different ways n can be expressed as a sum of integer powers of 2 using
5+
each power no more than twice.
6+
7+
For example, f(10) = 5 since there are five different ways to express 10:
8+
1+1+8
9+
1+1+4+4
10+
1+1+2+2+4
11+
2+4+4
12+
2+8
13+
14+
What is f(10^25)?
15+
16+
ANSWER: 178653872807
17+
Solve time ~0.001 seconds
18+
"""
19+
20+
# 10 = 8 + 2 = 2^3 + 2^1 = 1010 in binary
21+
# 1010 = 0210 = 1002 = 0202 = 0122
22+
# Therefore 5 ways to represent 10 using powers of 2 with no more than 2 of each power
23+
# idea: 1000 -> 0200 -> 0120 -> 0111, etc
24+
# key idea is the (# zeros after 1) when in binary is what matters to count the number of options
25+
# however we can't simply take the product of all the (# zeros after 1) + 1 since that undercounts the following case:
26+
# 1010 can become 0210, 1002, 0202, but also 0122, so to count this extra case when we remove the leading one,
27+
# this is as if we added some cases in which the number of consecutive zeros grows
28+
29+
# e.g. 18
30+
# - 10010
31+
# - 10002
32+
# - 02010
33+
# - 01210
34+
# - 02002
35+
# - 01202
36+
# - 01122
37+
from util.utils import timeit
38+
import unittest
39+
40+
41+
class Problem169:
42+
def __init__(self):
43+
pass
44+
45+
@timeit
46+
def solve(self, n):
47+
"""f_i = f_{i-1} + zeros[i] * sum_{k=1 to i-1} f_k"""
48+
n_binary_str = bin(n)[2:]
49+
ls_len_consecutive_zeros = [len(x) for x in n_binary_str.split('1')][1:] # first one is always 0
50+
result, rolling_sum = 1, 1
51+
for len_consecutive_zeros in ls_len_consecutive_zeros:
52+
result += len_consecutive_zeros * rolling_sum
53+
rolling_sum += result
54+
return result
55+
56+
57+
class Solution169(unittest.TestCase):
58+
def setUp(self):
59+
self.problem = Problem169()
60+
61+
def test_sample_solution_1(self):
62+
self.assertEqual(5, self.problem.solve(n=10))
63+
64+
def test_sample_solution_2(self):
65+
self.assertEqual(7, self.problem.solve(n=18))
66+
67+
def test_sample_solution_3(self):
68+
self.assertEqual(13, self.problem.solve(n=42))
69+
70+
def test_solution(self):
71+
self.assertEqual(178653872807, self.problem.solve(n=pow(10,25)))
72+
73+
74+
if __name__ == '__main__':
75+
unittest.main()
76+

0 commit comments

Comments
 (0)