Цифри занадто великі для публікації, тому ось вони на Пастебіні: число 1 , число 2 .
Перше число - це 600^2 = 360000
. Друге число те саме, за винятком наступних змін:
Positions to change to "2": 605, 1811, 3001, 6603
Positions to change to "4": 1805, 3003, 57348, 208895
Positions to change to "5": 602, 1201, 2405, 3004
Positions to change to "6": 1203, 1802
Positions to change to "7": 12, 609, 5401, 7200
Positions to change to "8": 1, 2, 4, 6, 600, 1200, 1808, 2400, 3600, 4803
Обидва хешу 271088937720654725553339294593617693056
.
Пояснення
Давайте розглянемо першу половину коду:
lW% e# Read input number as string, and reverse
600/ e# Split every 600 digits, forming a 2D array
_z e# Duplicate and zip, swapping rows and columns
{ }% e# For both arrays...
JfbDb e# Find sum of S[i][j]*13^i*19^j, where S are the character values
e# and the indices are from right to left, starting at 0.
GK# e# Take modulo 16^20
... ... e# (Rest of code irrelevant)
Тож якщо ми можемо знайти два вхідні числа, щоб суми S[i][j]*13^i*19^j
були однаковими за модулем16^20
як для початкового масиву в 600, так і для заархівованого масиву, ми закінчили.
Щоб зробити це трохи простішим, ми розглянемо лише 600^2 = 360000
-значити вхідні числа, так що масив із широким діапазоном 600 - це просто 600 на 600 квадратних цифр. Це полегшує візуалізацію і з цього часу діє 10^360000 ~ 2^(2^20.19) < 2^(2^30)
. Для подальшого спрощення речей ми розглянемо лише такі вхідні рядки, чий цифровий квадрат є симетричним уздовж основної діагоналі, так що вихідний масив та масив на блискавці однакові. Це також дозволяє нам ігнорувати початкове обертання рядків та нумерацію правого лівого індексу, які скасовують один одного.
Щоб почати нас, ми можемо взяти перше число 360000
. Щоб отримати друге число, ми хочемо змінити це, змінивши деякі цифри так, щоб суми були однаковими за модулем 16^20
, зберігаючи симетричність квадратного розряду. Ми досягаємо цього, знаходячи список трійки, (i, j, k)
щоб
sum of k*(13^i 19^j + 19^i 13^j) == 0 mod 16^20
де 1 <= k <= 8
сума для збільшення цифри 1 на (тобто зміну на цифру від 2 до 9 - ми могли б включити 0, але вона нам не потрібна) і 0 <= i < j < 600
є парами індексу.
Після того як ми (i, j, k)
трійня, ми міняємо цифри на (i, j)
і (j, i)
для того 1+k
щоб отримати другий номер. Триплети були знайдені за допомогою алчного алгоритму зворотного відстеження, а для другого числа над цифрою квадрат виглядає так:
188181811111711 ...
815112111711111 ...
851611111111111 ...
116114118112111 ...
811115111111111 ...
121451111111111 ...
811111111111111 ...
111111111111111 ...
111811111111111 ...
171111111111111 ...
111111111111111 ...
111211111111111 ...
711111111111111 ...
111111111111111 ...
111111111111111 ...
............... .
............... .
............... .
Наприклад, (i, j, k) = (0, 1, 7)
відповідає зміні цифр (0, 1)
(позиції 600*0 + 1 = 1
) і (1, 0)
(позиції 600*1 + 0 = 600
) на 1 + 7 = 8
.
Ось зворотний трекер на Python 3, хоча ретельна перевірка виявила, що нам дуже пощастило, оскільки жодного зворотного треку насправді не відбулося:
n = 16**20
L = [(k *(pow(13,i,n)*pow(19,j,n) + pow(19,i,n)*pow(13,j,n)) % n, i, j, k)
for i in range(600) for j in range(600) for k in range(1, 9) if i < j]
L.sort(reverse=True)
stack = [(n, 0, [])]
while stack:
k, index, result = stack.pop()
if k == 0:
print(result)
break
if index == len(L):
continue
stack.append((k, index+1, result)) # Don't include triplet
if L[index][0] <= k:
stack.append((k - L[index][0], index+1, result + [L[index][1:]])) # Include
Для бонусу ось не дуже ефективний порт хешу в Python 3. Це було марно.