|
| 1 | +""" |
| 2 | +Project Euler Problem 912: https://projecteuler.net/problem=912 |
| 3 | +
|
| 4 | +Problem: |
| 5 | +Sum of squares of odd indices where the n-th positive integer does not contain |
| 6 | +three consecutive ones in its binary representation. |
| 7 | +
|
| 8 | +We define `s_n` as the n-th positive integer that does not contain three |
| 9 | +consecutive ones in its binary representation. Define `F(N)` to be the sum of |
| 10 | +`n^2` for all `n ≤ N` where `s_n` is odd. |
| 11 | +
|
| 12 | +You are given: |
| 13 | +F(10) = 199 |
| 14 | +
|
| 15 | +Find F(10^16) modulo 10^9 + 7. |
| 16 | +""" |
| 17 | + |
| 18 | +MOD = 10**9 + 7 |
| 19 | + |
| 20 | + |
| 21 | +def matrix_mult(a, b, mod=MOD): |
| 22 | + """Multiplies two matrices a and b under modulo""" |
| 23 | + return [ |
| 24 | + [ |
| 25 | + (a[0][0] * b[0][0] + a[0][1] * b[1][0]) % mod, |
| 26 | + (a[0][0] * b[0][1] + a[0][1] * b[1][1]) % mod, |
| 27 | + ], |
| 28 | + [ |
| 29 | + (a[1][0] * b[0][0] + a[1][1] * b[1][0]) % mod, |
| 30 | + (a[1][0] * b[0][1] + a[1][1] * b[1][1]) % mod, |
| 31 | + ], |
| 32 | + ] |
| 33 | + |
| 34 | + |
| 35 | +def matrix_pow(mat, exp, mod=MOD): |
| 36 | + """Efficiently computes matrix to the power exp under modulo""" |
| 37 | + res = [[1, 0], [0, 1]] |
| 38 | + base = mat |
| 39 | + |
| 40 | + while exp > 0: |
| 41 | + if exp % 2 == 1: |
| 42 | + res = matrix_mult(res, base, mod) |
| 43 | + base = matrix_mult(base, base, mod) |
| 44 | + exp //= 2 |
| 45 | + |
| 46 | + return res |
| 47 | + |
| 48 | + |
| 49 | +def fib_like_sequence(n, mod=MOD): |
| 50 | + """ |
| 51 | + Computes the n-th term in the Fibonacci-like sequence of numbers whose binary |
| 52 | + representation does not contain three consecutive 1s. |
| 53 | +
|
| 54 | + This sequence follows the recurrence relation: |
| 55 | + a_n = a_(n-1) + a_(n-2) + a_(n-3) |
| 56 | +
|
| 57 | + Returns the sequence value modulo `mod`. |
| 58 | + """ |
| 59 | + |
| 60 | + if n == 0: |
| 61 | + return 0 |
| 62 | + if n in (1, 2): # Merge comparisons |
| 63 | + return 1 |
| 64 | + |
| 65 | + # The recurrence relation can be represented using matrix exponentiation: |
| 66 | + t = [[1, 1], [1, 0]] # Fibonacci-like transformation matrix |
| 67 | + result = matrix_pow(t, n - 1, mod) |
| 68 | + |
| 69 | + return result[0][0] # This gives the n-th Fibonacci-like term |
| 70 | + |
| 71 | + |
| 72 | +def calculate_sum_of_squares(limit): |
| 73 | + """ |
| 74 | + Computes F(limit) which is the sum of squares of indices where s_n is odd. |
| 75 | +
|
| 76 | + Arguments: |
| 77 | + - limit: up to which value of n we compute F(N) |
| 78 | +
|
| 79 | + Returns: |
| 80 | + - the sum F(limit) modulo 10^9 + 7 |
| 81 | + """ |
| 82 | + |
| 83 | + total_sum = 0 |
| 84 | + |
| 85 | + for n in range(1, limit + 1): |
| 86 | + s_n = fib_like_sequence(n) # Get the n-th sequence number |
| 87 | + |
| 88 | + if s_n % 2 == 1: # Check if s_n is odd |
| 89 | + total_sum = (total_sum + n**2) % MOD # Add square of n to total sum |
| 90 | + |
| 91 | + return total_sum |
| 92 | + |
| 93 | + |
| 94 | +def solution(limit=10**16): |
| 95 | + """ |
| 96 | + The solution to compute F(limit) efficiently. |
| 97 | + This function returns F(10^16) modulo 10^9 + 7. |
| 98 | + """ |
| 99 | + |
| 100 | + return calculate_sum_of_squares(limit) |
| 101 | + |
| 102 | + |
| 103 | +if __name__ == "__main__": |
| 104 | + # We are given F(10) = 199, so let's test for N = 10 first. |
| 105 | + assert solution(10) == 199 |
| 106 | + |
| 107 | + # Now find F(10^16) |
| 108 | + print(f"The result is: {solution(10**16)}") |
0 commit comments