def smallest_collatz(seq, L): '''Return the smallest starting number > L for the modified Collatz sequence starting with the encoded move sequence seq.''' r, two_k, n3 = 0L, 1L, pow(3L, len(seq)) # The reverse Collatz sequence has the form b_n = (3*n b_0 + r_n)/2^(k_n). r_n, 2^(k_n) admit an # easy recurrence relationship vs. r_(n-1), 2^(k_(n-1)). for move in reversed(seq): if move == 'D': r *= 3 elif move == 'U': r, two_k = 3 * r - 2 * two_k, 4 * two_k elif move == 'd': r, two_k = 3 * r + two_k, 2 * two_k # Use the Chinese remainder theorem to derive the form b_n = 3^n x + a*r where a = multiplicative # inverse of 2^(k_n) mod 3^n. a is efficiently found using the extended Euclid algorithm. Convert # this to b_n = 3^n + R where 0 <= R < 3^n. R = extended_gcd(two_k, n3)[0] * r % n3 return n3 * int_ceil((L + 1. - R) / n3) + R
For a prime p let S(p) = (SUM (p-k)!) mod(p) for 1 <= k <= 5. For example, if p=7, (7-1)! + (7-2)! + (7-3)! + (7-4)! + (7-5)! = 6! + 5! + 4! + 3! + 2! = 720+120+24+6+2 = 872. As 872 mod(7) = 4, S(7) = 4. It can be verified that SUM S(p) = 480 for 5 <= p < 100. Find SUM S(p) for 5 <= p < 108. ============================================================ ''' from itertools import islice, imap from problem007 import primes from problem134 import extended_gcd inv_mod = lambda x, p: extended_gcd(x, p)[0] sum_S = lambda N, k: sum(S(p, k) for p in imap(long, primes('lt', N)) if p >= k) S = lambda p, k: reduce(lambda x, y: (x + y) % p, islice(p_minus_k_factorial_mod(p), k - 2)) def p_minus_k_factorial_mod(p): pk, x = p - 2, 1 while True: x *= inv_mod(pk, p) yield x pk -= 1 if __name__ == "__main__": print S(7, 5) # 4 print sum_S(10 ** 2, 5) # 480 print sum_S(10 ** 8, 5) # 139602943319822