|
| 1 | +# <https://projecteuler.net/problem=800> |
| 2 | +# <p> |
| 3 | +# An integer of the form $p^q q^p$ with prime numbers $p \neq q$ is called a <dfn>hybrid-integer</dfn>.<br> |
| 4 | +# For example, $800 = 2^5 5^2$ is a hybrid-integer. |
| 5 | +# </p> |
| 6 | +# <p> |
| 7 | +# We define $C(n)$ to be the number of hybrid-integers less than or equal to $n$.<br> |
| 8 | +# You are given $C(800) = 2$ and $C(800^{800}) = 10790$. |
| 9 | +# </p> |
| 10 | +# <p> |
| 11 | +# Find $C(800800^{800800})$. |
| 12 | +# </p> |
| 13 | +# Notes: |
| 14 | +# - sqrt(800800^800800) = HUGE |
| 15 | +# - log2(800800^800800) < 1.6 x 10^7 |
| 16 | +# - Largest prime less than 1.6 x 10^7 is 1,599,9989 |
| 17 | +# - Number of primes < 1.6 x 10^7 is 1,031,130 |
| 18 | +# - log3(800800^800800) < 1.0 x 10^7 |
| 19 | +# - Largest prime less than 1.0 x 10^7 is 9999_991 |
| 20 | +# - Number of primes < 1.0 x 10^7 is 664579 |
| 21 | +# - log5(800800^800800) < 6.8 x 10^6 |
| 22 | +# - Largest prime less than is ?? |
| 23 | +# - Number of primes less than is ?? |
| 24 | +# - log7(800800^800800) < 5.6 x 10^6 |
| 25 | +# - Largest prime less than is ?? |
| 26 | +# - Number of primes less than is ?? |
| 27 | +# - p^q * q^p = h |
| 28 | +# - log(p^q) + log(q^p) = log(h) |
| 29 | +# - q*log(p) + p*log(q) = log(h) |
| 30 | +# - Assume p = 2 and use log base q |
| 31 | +# - q*logq(2) + 2*1 = logq(h) |
| 32 | +# - q = 15999989 |
| 33 | +# - 668574.6 =(?) logq(800800^800800) = 656227.6 |
| 34 | + |
| 35 | +import pytest |
| 36 | +import numpy |
| 37 | +import math |
| 38 | +from decimal import Decimal |
| 39 | + |
| 40 | +# <https://stackoverflow.com/a/3035188> |
| 41 | +def primesfrom2to(n): |
| 42 | + """ Input n>=6, Returns a array of primes, 2 <= p < n """ |
| 43 | + sieve = numpy.ones(n//3 + (n%6==2), dtype=bool) |
| 44 | + for i in range(1,int(n**0.5)//3+1): |
| 45 | + if sieve[i]: |
| 46 | + k=3*i+1|1 |
| 47 | + sieve[ k*k//3 ::2*k] = False |
| 48 | + sieve[k*(k-2*(i&1)+4)//3::2*k] = False |
| 49 | + return numpy.r_[2,3,((3*numpy.nonzero(sieve)[0][1:]+1)|1)] |
| 50 | + |
| 51 | +def test_can_get_primes(): |
| 52 | + primes = primesfrom2to(16000000) |
| 53 | + assert len(primes) == 1031130 |
| 54 | + assert 15999989 == primes[-1] |
| 55 | + |
| 56 | +def C(n): |
| 57 | + largest_prime = math.ceil(log(n, 2)) |
| 58 | + primes = primesfrom2to(largest_prime) |
| 59 | + numberOfPrimes = len(primes) |
| 60 | + print(numberOfPrimes) |
| 61 | + count = 0 |
| 62 | + for i in range(numberOfPrimes): |
| 63 | + p = primes[i] |
| 64 | + nLog = log(n, p) |
| 65 | + count += max(binary_search(primes, nLog, lambda q: p * log(q, p) + q) - i, 0) |
| 66 | + if i % 100000 == 0: |
| 67 | + print(i) |
| 68 | + return count |
| 69 | + |
| 70 | +def log(number, base): |
| 71 | + return math.log(number, base) |
| 72 | + |
| 73 | +def binary_search(a, nLog, function): |
| 74 | + lo = 0 |
| 75 | + hi = len(a) |
| 76 | + while lo < hi: |
| 77 | + mid = (lo+hi)//2 |
| 78 | + midval = function(a[mid]) |
| 79 | + if midval < nLog: |
| 80 | + lo = mid + 1 |
| 81 | + elif midval > nLog: |
| 82 | + hi = mid |
| 83 | + else: |
| 84 | + return mid |
| 85 | + return hi - 1 |
| 86 | + |
| 87 | +@pytest.mark.skip(reason="48s to solve") |
| 88 | +def test_C_works_for_examples(): |
| 89 | + """You are given $C(800) = 2$ and $C(800^{800}) = 10790$.""" |
| 90 | + # assert C(800) == 2 |
| 91 | + # assert C(800**800) == 10790 |
| 92 | + # assert C(8008**8008) == 440302 |
| 93 | + # assert C(80080**8008) == 621290 |
| 94 | + # assert C(80080**80080) == 23036066 |
| 95 | + # assert C(800800**80080) == 31110609 |
| 96 | + assert C(800800**800800) == 1412403576 |
| 97 | + |
0 commit comments