Jumlahnya terlalu besar untuk dikirim, jadi di sini mereka berada di Pastebin: num 1 , num 2 .
Angka pertama adalah 600^2 = 360000
yang. Angka kedua sama, kecuali untuk perubahan berikut:
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
Keduanya hash 271088937720654725553339294593617693056
.
Penjelasan
Mari kita lihat pada bagian pertama dari kode:
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)
Jadi jika kita dapat menemukan dua angka input sehingga jumlah S[i][j]*13^i*19^j
modulo yang sama 16^20
untuk array 600-lebar awal dan array zip, maka kita sudah selesai.
Untuk mempermudah, kami hanya akan mempertimbangkan 600^2 = 360000
angka input -digit, sehingga array 600-lebar hanya 600 x 600 persegi digit. Ini membuat segalanya lebih mudah untuk divisualisasikan, dan valid sejak saat itu 10^360000 ~ 2^(2^20.19) < 2^(2^30)
. Untuk menyederhanakan hal-hal lebih jauh, kami hanya akan mempertimbangkan string input seperti itu yang digit perseginya simetris di sepanjang diagonal utama, sehingga array asli dan array zip sama. Ini juga memungkinkan kita untuk mengabaikan pembalikan string awal dan penomoran indeks kanan-ke-kiri, yang membatalkan satu sama lain.
Untuk memulai kita, kita bisa mengambil nomor pertama menjadi 360000
yang pertama. Untuk mendapatkan angka kedua, kami ingin memodifikasi ini dengan mengubah beberapa digit sehingga jumlahnya adalah modulo yang sama 16^20
, sambil mempertahankan simetri digit persegi. Kami menyelesaikan ini dengan menemukan daftar tiga kali lipat (i, j, k)
sehingga
sum of k*(13^i 19^j + 19^i 13^j) == 0 mod 16^20
di mana 1 <= k <= 8
jumlah untuk meningkatkan digit 1 oleh (yaitu mengubah ke digit dari 2 menjadi 9 - kita bisa memasukkan 0 tetapi kita tidak membutuhkannya) dan 0 <= i < j < 600
merupakan pasangan indeks.
Setelah kita memiliki (i, j, k)
kembar tiga, kita mengubah angka di (i, j)
dan (j, i)
untuk 1+k
mendapatkan angka kedua. Si kembar tiga ditemukan menggunakan algoritma backtracking serakah, dan untuk angka kedua di atas digit persegi terlihat seperti:
188181811111711 ...
815112111711111 ...
851611111111111 ...
116114118112111 ...
811115111111111 ...
121451111111111 ...
811111111111111 ...
111111111111111 ...
111811111111111 ...
171111111111111 ...
111111111111111 ...
111211111111111 ...
711111111111111 ...
111111111111111 ...
111111111111111 ...
............... .
............... .
............... .
Misalnya, (i, j, k) = (0, 1, 7)
terkait dengan mengubah digit (0, 1)
(posisi 600*0 + 1 = 1
) dan (1, 0)
(posisi 600*1 + 0 = 600
) menjadi 1 + 7 = 8
.
Inilah backtracker di Python 3, meskipun inspeksi lebih dekat mengungkapkan bahwa kami cukup beruntung, karena tidak ada backtracking yang sebenarnya terjadi:
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
Sebagai bonus, ini adalah port hash yang tidak terlalu efisien dalam Python 3. Itu tidak berguna.