Challenge: Bear And Cryptography
Subdomeniu: Number Theory (number-theory)
Scor cont: 100.0 / 100
Submission status: Accepted
Submission score: 1.0
Submission ID: 464776295
Limbaj: python3
Link challenge: https://www.hackerrank.com/challenges/bear-and-cryptography/problem
Cerinta
Limak is a little bear who loves school. Today was his first lesson in cryptography, and the teacher assigned some difficult homework—to find any number with exactly $K$ divisors. Limak wants to go the extra mile and find the biggest possible number; however, his teacher explained that there are arbitrarily large numbers with this property.
To give this little bear a more achievable challenge, the teacher advised him to consider only numbers not greater than $N$.
Given $N$ and $K$, what is the largest number Limak can find?
Input Format
The first line contains an integer, $T$ (the number of test cases).
The $T$ subsequent lines of test cases each contain two space-separated integers, $N$ and $K$, respectively.
Output Format
For each test case, print the biggest number Limak can find on a new line. Print $-1$ if no such number exists.
Constraints
* $1 \le T \le 50$
* $1 \le N \le 10^{12}$
* $1 \le K \le 40$
Cod sursa
#!/bin/python3
import math
import random
def gcd(a, b):
while b > 0:
c = a % b
a = b
b = c
return a
def is_prime(k):
small = [2,3,5,7,11]
if k in small:
return True
if k % 2 == 0:
return False
odd = k - 1
e = 0
while odd % 2 == 0:
e += 1
odd = odd//2
for p in small:
num = pow(p, odd, k)
check = False
if num == 1 or num == k - 1:
continue
for i in range(e):
num = pow(num, 2, k)
if num == k - 1:
check = True
break
if num == 1:
return False
if not check and num != 1:
return False
return True
factorizations = [[],
[],
[[2]],
[[3]],
[[4], [2, 2]],
[[5]],
[[6], [3, 2]],
[[7]],
[[8], [4, 2], [2, 2, 2]],
[[9], [3, 3]],
[[10], [5, 2]],
[[11]],
[[12], [6, 2], [3, 2, 2], [4, 3]],
[[13]],
[[14], [7, 2]],
[[15], [5, 3]],
[[16], [8, 2], [4, 2, 2], [2, 2, 2, 2], [4, 4]],
[[17]],
[[18], [9, 2], [3, 3, 2], [6, 3]],
[[19]],
[[20], [10, 2], [5, 2, 2], [5, 4]],
[[21], [7, 3]],
[[22], [11, 2]],
[[23]],
[[24], [12, 2], [6, 2, 2], [3, 2, 2, 2], [4, 3, 2], [8, 3], [6, 4]],
[[25], [5, 5]],
[[26], [13, 2]],
[[27], [9, 3], [3, 3, 3]],
[[28], [14, 2], [7, 2, 2], [7, 4]],
[[29]],
[[30], [15, 2], [5, 3, 2], [10, 3], [6, 5]],
[[31]],
[[32], [16, 2], [8, 2, 2], [4, 2, 2, 2], [2, 2, 2, 2, 2], [4, 4, 2], [8, 4]],
[[33], [11, 3]],
[[34], [17, 2]],
[[35], [7, 5]],
[[36],
[18, 2],
[9, 2, 2],
[3, 3, 2, 2],
[6, 3, 2],
[12, 3],
[4, 3, 3],
[9, 4],
[6, 6]],
[[37]],
[[38], [19, 2]],
[[39], [13, 3]],
[[40], [20, 2], [10, 2, 2], [5, 2, 2, 2], [5, 4, 2], [10, 4], [8, 5]]]
'''
factorizations = [[],[],[[2]]]
def same_arr(a, b):
a = [i for i in a]
b = [j for j in b]
if len(a) != len(b):
return False
for thing in a:
if thing not in b:
return False
b.remove(thing)
return True
for i in range(3, 41):
facts = [[i]]
if is_prime(i):
factorizations.append(facts)
continue
for j in range(2, int(i**.5) + 1):
if i % j == 0:
fact = [j]
for other_fact in factorizations[i//j]:
new_fact = fact + other_fact
app = True
for thing in facts:
if same_arr(thing, new_fact):
app = False
break
if app:
facts.append(fact + other_fact)
factorizations.append(facts)
'''
def sieve(bound):
arr = [1 for i in range(bound - 2)]
arr.insert(0, 0)
arr.insert(0, 0)
ps = []
l = len(arr)
sq = 0
for i, val in enumerate(arr):
if sq > bound:
break
elif val == 1:
ind = i
ps.append(i)
for ind in range(sq, l, i):
arr[ind] = 0
sq = sq + 2* i + 1
for j in range(i, l):
if arr[j] == 1:
ps.append(j)
return ps
primes = sieve(1000)
bigPrimes = sieve(pow(10, 6))
smallPrimes = sieve(30)
midPrimes = sieve(1000)
def num_divs(d):
prod = 1
for k, v in d.items():
prod = prod * (v + 1)
return prod
def pollard_rho(n):
while True:
c = random.randint(2, n-1)
f = lambda x: x**2 + c
x = y = 2
d = 1
while d == 1:
x = f(x) % n
y = f(f(y)) % n
d = gcd((x - y) % n, n)
if d != n: return d
def smart_factor(n):
d = dict()
for div in primes:
while n % div == 0:
if div in d:
d[div] += 1
else:
d[div] = 1
n = n // div
if n == 1:
break
if n == 1:
return d
if not is_prime(n):
div = pollard_rho(n) #parameters should be chosen so that n has at most 4 prime factors
divs = []
n = n // div
if not is_prime(n):
div2 = pollard_rho(n)
div3 = n // div2
if not is_prime(div2):
div4 = pollard_rho(div2)
div5 = div2 // div4
divs.append(div4)
divs.append(div5)
else:
divs.append(div2)
if not is_prime(div3):
div4 = pollard_rho(div3)
div5 = div3 // div4
divs.append(div4)
divs.append(div5)
else:
divs.append(div3)
else:
divs.append(n)
if not is_prime(div):
div2 = pollard_rho(div)
div3 = div // div2
if not is_prime(div2):
div4 = pollard_rho(div2)
div5 = div2 // div4
divs.append(div4)
divs.append(div5)
else:
divs.append(div2)
if not is_prime(div3):
div4 = pollard_rho(div3)
div5 = div3 // div4
divs.append(div4)
divs.append(div5)
else:
divs.append(div3)
else:
divs.append(div)
for div in divs:
if div in d:
d[div] += 1
else:
d[div] = 1
else:
d[n] = 1
return d
def condition(sq, n):
if sq**2 <= n and (sq + 1)**2 > n:
return True
return False
def int_sqrt(n):
guess = n // 2
while not condition(guess, n):
guess = (guess + n//guess) // 2
return guess
def all_twos(a):
for thing in a:
if thing > 4:
return False
return True
def all_threes(a):
for thing in a:
if thing != 3:
return False
return True
#Implement 9, 27, and 30 better.
#if it's 9, we only check primes up to the 4th root of n. Symmetry tells us this should work.
#if it's 27, the smallest number has to be less than 100-ish by symmetry. Check the primes up
#to 100-ish for the smallest prime, and then it reduces to 9. Don't forget to check the other
#factorizations of 27, but those are really fast.
#if it's 30, the 4th power must correspond to a number less than 13-ish, the 2nd power must be
#less than 200-ish, and that should not be a hard check. Again don't forget to check the other
#factorizations of 30.
def solve_9(n, i):
biggest = -1
if n < 2:
return -1
for j in range(i, len(midPrimes)):
p = midPrimes[j]
res = n//pow(p, 2)
if res <= 3:
break
num = int_sqrt(res)
while num > p and not is_prime(num):
num = num - 1
if num <= p:
break
ans = pow(p, 2) * pow(num, 2)
if ans > biggest:
biggest = ans
return biggest
def solve_27(n):
biggest = -1
for i in range(len(midPrimes)):
p = midPrimes[i]
ans = solve_9(n//pow(p,2), i+1)
if ans*pow(p, 2) > biggest:
biggest = ans*pow(p,2)
return biggest
def solve_30(n):
biggest = -1
n2 = n
for p in smallPrimes:
for q in midPrimes:
if p != q:
n = n2
n = n // pow(p, 4)
n = n // pow(q, 2)
while n > 1 and not is_prime(n):
n = n - 1
ans = n * pow(p, 4) * pow(q, 2)
if ans > biggest:
biggest = ans
return biggest
def solve(n, fact):
if n < 2:
return -1
if len(fact) == 1:
root = fact[0] - 1
n2 = int(n**(1/root))
while n2**root < n:
n2 += 1
while n2**root > n and n2 > 1:
n2 = n2 - 1
if n2 <= 1:
return -1
while n2 > 1 and not is_prime(n2):
n2 = n2 - 1
if n2 == 1:
return -1
return pow(n2, root)
ans = 0
i = 0
biggest = -1
while ans != -1:
base = pow(bigPrimes[i], fact[0] - 1)
start = n // base
root = fact[1] - 1
n2 = int(start**(1/root))
while n2**root < start:
n2 += 1
while n2**root > start and n2 > 1:
n2 = n2 - 1
if n2 <= 1:
break
while (n2 > 1 and not is_prime(n2)) or n2 == bigPrimes[i]:
n2 = n2 - 1
if n2 == 1:
break
ans = n2**root
if ans*base > biggest:
biggest = ans*base
i += 1
return biggest
if __name__ == '__main__':
T = int(input())
#begin = time.time()
for thing in range(T):
NK = input().split()
N = int(NK[0])
K = int(NK[1])
if K == 1:
print(1)
continue
if K == 2:
if N == 1:
print(-1)
continue
while not is_prime(N):
N = N - 1
print(N)
continue
if is_prime(K):
root = K - 1
N2 = int(N**(1/root))
while N2**root < N:
N2 += 1
if N2**root > N:
N2 = N2 - 1
if N2 <= 1:
print(-1)
continue
while not is_prime(N2):
N2 = N2 - 1
print(pow(N2, root))
continue
biggest = -1
if (len(factorizations[K]) == 2 and (K != 4 and K != 6)) or (K in [27, 30]):
for thing in factorizations[K]:
if thing == [3, 3]:
ans = solve_9(N, 0)
elif thing == [3,3,3]:
ans = solve_27(N)
elif thing == [5,3,2]:
ans = solve_30(N)
else:
ans = solve(N, thing)
if ans > biggest:
biggest = ans
print(biggest)
else:
d = smart_factor(N)
while num_divs(d) != K:
N = N - 1
d = smart_factor(N)
print(N)
HackerRank Number Theory – Bear And Cryptography
