from math import inf
, ceil, gcd
from itertools import groupby, accumulate
from operator import mul
from random import randrange
def isqrt(n):
if n < 0:
raise ValueError
("x must be non-negative") if n == 0:
return 0
x = 2 ** ((n.bit_length() - 1) // 2 + 1) # x > sqrt(n)
y = x - 1
while y < x:
x = y
y = (x + n//x) // 2
return x
def iroot(k, n):
'ínt kth root - uses Newton'
if k == 2:
return isqrt(n)
if n < 0:
if k % 2:
return -iroot(k, -n)
else:
raise ValueError
("n must be non-negative") if k < 0:
raise ValueError
("k must be non-negative") if n in (0, 1):
return n
km1 = k-1
s = 2 ** ((n.bit_length() - 1)//k + 1)
u = s - 1
while u < s:
s = u
u = (km1*s + n // s**km1) // k
return s
_small_primes = set((2, 3, 5, 7, 11, 13, 17, 19, 23))
def is_prime(n, k=25):
""" Miller-Rabin
returns: True if n is probably prime
False if n is composite
k: number of random trial used
"""
if n < 29:
return n in _small_primes
for pi in _small_primes:
if not n % pi:
return False
return False
d, s = n - 1, 0
while not d % 2:
d //= 2
s += 1
def is_spsp(n, a):
if t in (1, n-1):
return True
for _ in range(s-1):
t = (t * t) % n
if t == n - 1:
return True
if t == 1:
return False
return False
return all(is_spsp(n, randrange(2, n-1)) for _ in range(k))
def pollard_rho(n, c=3):
t, h, d = 2, 2, 1
while d == 1:
t = (t * t + c) % n
h = (h * h + c) % n
h = (h * h + c) % n
d = gcd(t - h, n)
if d == n: # cycle detected
return pollard_rho(n, c + 1)
return d
def rho_factors(n):
if n < 2:
return [-1] + rho_factors(-n) if n < 0 else []
fs = []
while not n % 2:
n //= 2
fs.append(2)
while not (is_prime(n) or n == 1):
f = pollard_rho(n)
flist = [f] if is_prime(f) else rho_factors(f)
for f in flist:
while not n % f:
n //= f
fs.append(f)
if n > 1:
fs.append(n)
return sorted(fs)
def divisors_from_factors(factors):
"""FAST - list of all divisors from factors"""
fact = [(1,) + tuple(accumulate(g, mul)) for _, g in groupby(factors)]
for g in fact:
div = [d
* f
for d in
div for f in g
]
def divisors(n, factor_gen=rho_factors):
"""FAST - list of all divisors of n"""
return divisors_from_factors(factor_gen(n))
def bf(n):
"""i <= j <= p"""
tmin = inf
fmin = None
n3
= ceil(n
** (1/3)) + 1 for i in range(1, n3):
if n % i == 0:
m = n // i
m2
= ceil(m
** (1/2)) + 1 for j in range(i, m2):
if m % j == 0:
p = m // j
s = i + j + p
if s < tmin:
tmin = s
fmin = i, j, p
return fmin, tmin
def threeway(n):
divs = sorted(divisors(n), reverse=True)
n3 = iroot(3, n)
min_val, min_sol = inf, None
for x in divs:
if x > n3:
continue
m = n // x
sqrtm = isqrt(m)
if x + sqrtm + m // sqrtm >= min_val:
break
for y in divs:
if y < x:
break
if y > sqrtm:
continue
if m % y == 0:
z = m // y
if x + y + z < min_val:
min_sol, min_val = (x, y, z), x + y + z
break
return min_sol, min_val
N = 1890
print(N)
print(threeway(N))
M = 10**40
N = randrange(M, 2*M)
print(N)
print(threeway(N))
if False:
for n in range(100000+1, 200000+1):
if n % 1000 == 0:
print("n=", n)
f1, s1 = bf(n)
f3, s3 = threeway(n)
assert s1
== s3
, "{} {} {} {} {} {}".
format(n
, s1
, s3
, facs
, f1
, f3
)
print("Test OK")
if False:
N1 = 10**12
N2 = N1 + 1
for n in range(N1, N2):
f1, s1 = threeway(n)
for n in range(N1, N2):
f1, s1 = bf(n)
ZnJvbSBtYXRoIGltcG9ydCBpbmYsIGNlaWwsIGdjZApmcm9tIHRpbWUgaW1wb3J0IGNsb2NrCmZyb20gaXRlcnRvb2xzIGltcG9ydCBncm91cGJ5LCBhY2N1bXVsYXRlCmZyb20gb3BlcmF0b3IgaW1wb3J0IG11bApmcm9tIHJhbmRvbSBpbXBvcnQgcmFuZHJhbmdlCgpkZWYgaXNxcnQobik6CiAgICBpZiBuIDwgMDoKICAgICAgICByYWlzZSBWYWx1ZUVycm9yKCJ4IG11c3QgYmUgbm9uLW5lZ2F0aXZlIikKICAgIGlmIG4gPT0gMDoKICAgICAgICByZXR1cm4gMAogICAgeCA9IDIgKiogKChuLmJpdF9sZW5ndGgoKSAtIDEpIC8vIDIgKyAxKSAgICAjIHggPiBzcXJ0KG4pCiAgICB5ID0geCAtIDEKICAgIHdoaWxlIHkgPCB4OgogICAgICAgIHggPSB5CiAgICAgICAgeSA9ICh4ICsgbi8veCkgLy8gMgogICAgcmV0dXJuIHgKCmRlZiBpcm9vdChrLCBuKToKICAgICfDrW50IGt0aCByb290IC0gdXNlcyBOZXd0b24nCiAgICBpZiBrID09IDI6CiAgICAgICAgcmV0dXJuIGlzcXJ0KG4pCiAgICBpZiBuIDwgMDoKICAgICAgICBpZiBrICUgMjoKICAgICAgICAgICAgcmV0dXJuIC1pcm9vdChrLCAtbikKICAgICAgICBlbHNlOgogICAgICAgICAgICByYWlzZSBWYWx1ZUVycm9yKCJuIG11c3QgYmUgbm9uLW5lZ2F0aXZlIikKICAgIGlmIGsgPCAwOgogICAgICAgIHJhaXNlIFZhbHVlRXJyb3IoImsgbXVzdCBiZSBub24tbmVnYXRpdmUiKQogICAgaWYgbiBpbiAoMCwgMSk6CiAgICAgICAgcmV0dXJuIG4KICAgIGttMSA9IGstMQogICAgcyA9IDIgKiogKChuLmJpdF9sZW5ndGgoKSAtIDEpLy9rICsgMSkKICAgIHUgPSBzIC0gMQogICAgd2hpbGUgdSA8IHM6CiAgICAgICAgcyA9IHUKICAgICAgICB1ID0gKGttMSpzICsgbiAvLyBzKiprbTEpIC8vIGsKICAgIHJldHVybiBzCgpfc21hbGxfcHJpbWVzID0gc2V0KCgyLCAzLCA1LCA3LCAxMSwgMTMsIDE3LCAxOSwgMjMpKQoKZGVmIGlzX3ByaW1lKG4sIGs9MjUpOgogICAgIiIiIE1pbGxlci1SYWJpbgogICAgICAgIHJldHVybnM6IFRydWUgaWYgbiBpcyBwcm9iYWJseSBwcmltZQogICAgICAgICAgICAgICAgICAgIEZhbHNlIGlmIG4gaXMgY29tcG9zaXRlCiAgICAgICAgazogbnVtYmVyIG9mIHJhbmRvbSB0cmlhbCB1c2VkCiAgICAiIiIKICAgIG4gPSBhYnMobikKICAgIGlmIG4gPCAyOToKICAgICAgICByZXR1cm4gbiBpbiBfc21hbGxfcHJpbWVzCiAgICBmb3IgcGkgaW4gX3NtYWxsX3ByaW1lczoKICAgICAgICBpZiBub3QgbiAlIHBpOgogICAgICAgICAgICByZXR1cm4gRmFsc2UKICAgIGlmIHBvdygyLCBuLTEsIG4pICE9IDE6CiAgICAgICAgcmV0dXJuIEZhbHNlCiAgICBkLCBzID0gbiAtIDEsIDAKICAgIHdoaWxlIG5vdCBkICUgMjoKICAgICAgICBkIC8vPSAyCiAgICAgICAgcyArPSAxCgogICAgZGVmIGlzX3Nwc3AobiwgYSk6CiAgICAgICAgdCA9IHBvdyhhLCBkLCBuKQogICAgICAgIGlmIHQgaW4gKDEsIG4tMSk6CiAgICAgICAgICAgIHJldHVybiBUcnVlCiAgICAgICAgZm9yIF8gaW4gcmFuZ2Uocy0xKToKICAgICAgICAgICAgdCA9ICh0ICogdCkgJSBuCiAgICAgICAgICAgIGlmIHQgPT0gbiAtIDE6CiAgICAgICAgICAgICAgICByZXR1cm4gVHJ1ZQogICAgICAgICAgICBpZiB0ID09IDE6CiAgICAgICAgICAgICAgICByZXR1cm4gRmFsc2UKICAgICAgICByZXR1cm4gRmFsc2UKICAgIHJldHVybiBhbGwoaXNfc3BzcChuLCByYW5kcmFuZ2UoMiwgbi0xKSkgZm9yIF8gaW4gcmFuZ2UoaykpCgpkZWYgcG9sbGFyZF9yaG8obiwgYz0zKToKICAgIHQsIGgsIGQgPSAyLCAyLCAxCiAgICB3aGlsZSBkID09IDE6CiAgICAgICAgdCA9ICh0ICogdCArIGMpICUgbgogICAgICAgIGggPSAoaCAqIGggKyBjKSAlIG4KICAgICAgICBoID0gKGggKiBoICsgYykgJSBuCiAgICAgICAgZCA9IGdjZCh0IC0gaCwgbikKICAgIGlmIGQgPT0gbjogICMgY3ljbGUgZGV0ZWN0ZWQKICAgICAgICByZXR1cm4gcG9sbGFyZF9yaG8obiwgYyArIDEpCiAgICByZXR1cm4gZAoKZGVmIHJob19mYWN0b3JzKG4pOgogICAgaWYgbiA8IDI6CiAgICAgICAgcmV0dXJuIFstMV0gKyByaG9fZmFjdG9ycygtbikgaWYgbiA8IDAgZWxzZSBbXQogICAgZnMgPSBbXQogICAgd2hpbGUgbm90IG4gJSAyOgogICAgICAgIG4gLy89IDIKICAgICAgICBmcy5hcHBlbmQoMikKICAgIHdoaWxlIG5vdCAoaXNfcHJpbWUobikgb3IgbiA9PSAxKToKICAgICAgICBmID0gcG9sbGFyZF9yaG8obikKICAgICAgICBmbGlzdCA9IFtmXSBpZiBpc19wcmltZShmKSBlbHNlIHJob19mYWN0b3JzKGYpCiAgICAgICAgZm9yIGYgaW4gZmxpc3Q6CiAgICAgICAgICAgIHdoaWxlIG5vdCBuICUgZjoKICAgICAgICAgICAgICAgIG4gLy89IGYKICAgICAgICAgICAgICAgIGZzLmFwcGVuZChmKQogICAgaWYgbiA+IDE6CiAgICAgICAgZnMuYXBwZW5kKG4pCiAgICByZXR1cm4gc29ydGVkKGZzKQoKZGVmIGRpdmlzb3JzX2Zyb21fZmFjdG9ycyhmYWN0b3JzKToKICAgICIiIkZBU1QgLSBsaXN0IG9mIGFsbCBkaXZpc29ycyBmcm9tIGZhY3RvcnMiIiIKICAgIGZhY3QgPSBbKDEsKSArIHR1cGxlKGFjY3VtdWxhdGUoZywgbXVsKSkgZm9yIF8sIGcgaW4gZ3JvdXBieShmYWN0b3JzKV0KICAgIGRpdiA9IFsxXQogICAgZm9yIGcgaW4gZmFjdDoKICAgICAgICBkaXYgPSBbZCAqIGYgZm9yIGQgaW4gZGl2IGZvciBmIGluIGddCiAgICByZXR1cm4gZGl2CgpkZWYgZGl2aXNvcnMobiwgZmFjdG9yX2dlbj1yaG9fZmFjdG9ycyk6CiAgICAiIiJGQVNUIC0gbGlzdCBvZiBhbGwgZGl2aXNvcnMgb2YgbiIiIgogICAgcmV0dXJuIGRpdmlzb3JzX2Zyb21fZmFjdG9ycyhmYWN0b3JfZ2VuKG4pKQoKZGVmIGJmKG4pOgogICAgIiIiaSA8PSBqIDw9IHAiIiIKICAgIHRtaW4gPSBpbmYKICAgIGZtaW4gPSBOb25lCiAgICBuMyA9IGNlaWwobiAqKiAoMS8zKSkgKyAxCiAgICBmb3IgaSBpbiByYW5nZSgxLCBuMyk6CiAgICAgICAgaWYgbiAlIGkgPT0gMDoKICAgICAgICAgICAgbSA9IG4gLy8gaQogICAgICAgICAgICBtMiA9IGNlaWwobSAqKiAoMS8yKSkgKyAxCiAgICAgICAgICAgIGZvciBqIGluIHJhbmdlKGksIG0yKToKICAgICAgICAgICAgICAgIGlmIG0gJSBqID09IDA6CiAgICAgICAgICAgICAgICAgICAgcCA9IG0gLy8gagogICAgICAgICAgICAgICAgICAgIHMgPSBpICsgaiArIHAKICAgICAgICAgICAgICAgICAgICBpZiBzIDwgdG1pbjoKICAgICAgICAgICAgICAgICAgICAgICAgdG1pbiA9IHMKICAgICAgICAgICAgICAgICAgICAgICAgZm1pbiA9IGksIGosIHAKICAgIHJldHVybiBmbWluLCB0bWluCgpkZWYgdGhyZWV3YXkobik6CiAgICBkaXZzID0gc29ydGVkKGRpdmlzb3JzKG4pLCByZXZlcnNlPVRydWUpCiAgICBuMyA9IGlyb290KDMsIG4pCiAgICBtaW5fdmFsLCBtaW5fc29sID0gaW5mLCBOb25lCiAgICBmb3IgeCBpbiBkaXZzOgogICAgICAgIGlmIHggPiBuMzoKICAgICAgICAgICAgY29udGludWUKICAgICAgICBtID0gbiAvLyB4CiAgICAgICAgc3FydG0gPSBpc3FydChtKQogICAgICAgIGlmIHggKyBzcXJ0bSArIG0gLy8gc3FydG0gPj0gbWluX3ZhbDoKICAgICAgICAgICAgYnJlYWsKICAgICAgICBmb3IgeSBpbiBkaXZzOgogICAgICAgICAgICBpZiB5IDwgeDoKICAgICAgICAgICAgICAgIGJyZWFrCiAgICAgICAgICAgIGlmIHkgPiBzcXJ0bToKICAgICAgICAgICAgICAgIGNvbnRpbnVlCiAgICAgICAgICAgIGlmIG0gJSB5ID09IDA6CiAgICAgICAgICAgICAgICB6ID0gbSAvLyB5CiAgICAgICAgICAgICAgICBpZiB4ICsgeSArIHogPCBtaW5fdmFsOgogICAgICAgICAgICAgICAgICAgIG1pbl9zb2wsIG1pbl92YWwgPSAoeCwgeSwgeiksIHggKyB5ICsgegogICAgICAgICAgICAgICAgYnJlYWsKICAgIHJldHVybiBtaW5fc29sLCBtaW5fdmFsCiAgICAgICAgCk4gPSAxODkwCnByaW50KE4pCnByaW50KHRocmVld2F5KE4pKQpNID0gMTAqKjQwCk4gPSByYW5kcmFuZ2UoTSwgMipNKQpwcmludChOKQpwcmludCh0aHJlZXdheShOKSkKCmlmIEZhbHNlOgogICAgZm9yIG4gaW4gcmFuZ2UoMTAwMDAwKzEsIDIwMDAwMCsxKToKICAgICAgICBpZiBuICUgMTAwMCA9PSAwOgogICAgICAgICAgICBwcmludCgibj0iLCBuKQogICAgICAgIGYxLCBzMSA9IGJmKG4pCiAgICAgICAgZjMsIHMzID0gdGhyZWV3YXkobikKICAgICAgICBhc3NlcnQgczEgPT0gczMsICJ7fSB7fSB7fSB7fSB7fSB7fSIuZm9ybWF0KG4sIHMxLCBzMywgZmFjcywgZjEsIGYzKQoKICAgIHByaW50KCJUZXN0IE9LIikKCmlmIEZhbHNlOgogICAgTjEgPSAxMCoqMTIKICAgIE4yID0gTjEgKyAxCgogICAgdDAgPSBjbG9jaygpCiAgICBmb3IgbiBpbiByYW5nZShOMSwgTjIpOgogICAgICAgIGYxLCBzMSA9IHRocmVld2F5KG4pCiAgICBwcmludChjbG9jaygpIC0gdDApCgogICAgdDAgPSBjbG9jaygpCiAgICBmb3IgbiBpbiByYW5nZShOMSwgTjIpOgogICAgICAgIGYxLCBzMSA9IGJmKG4pCiAgICBwcmludChjbG9jaygpIC0gdDApCg==