Die Zahlen sind zu groß, um sie zu posten, also sind sie hier auf Pastebin: Nummer 1 , Nummer 2 .
Die erste Zahl ist 600^2 = 360000
eins. Die zweite Zahl ist bis auf die folgenden Änderungen identisch:
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
Beides muss Hash sein 271088937720654725553339294593617693056
.
Erläuterung
Werfen wir einen Blick auf die erste Hälfte des Codes:
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)
Also, wenn wir zwei Eingangszahlen finden können, so dass die Summen von S[i][j]*13^i*19^j
16^20
sowohl für das ursprüngliche 600-breite Array als auch für das gezippte Array dasselbe Modulo aufweisen , sind wir fertig.
Um die Sache ein wenig einfacher zu machen, werden wir nur darüber nachdenken 600^2 = 360000
-stellige Eingabenummern, so dass das 600-breite Array nur ein Quadrat mit 600 mal 600 Ziffern ist. Dies erleichtert die Visualisierung und ist seitdem gültig10^360000 ~ 2^(2^20.19) < 2^(2^30)
. Um die Sache noch weiter zu vereinfachen, betrachten wir nur solche Eingabezeichenfolgen, deren Ziffernquadrat entlang der Hauptdiagonale symmetrisch ist, so dass das ursprüngliche Array und das gezippte Array identisch sind. Dadurch können wir auch die anfängliche Umkehrung der Zeichenfolge und die Indexnummerierung von rechts nach links ignorieren, die sich gegenseitig aufheben.
Um uns anzufangen, können wir die erste Zahl als 360000
eine annehmen . Um die zweite Zahl zu erhalten, möchten wir diese ändern, indem wir einige der Ziffern so ändern, dass die Summen das gleiche Modulo haben 16^20
, wobei die Symmetrie des Ziffernquadrats erhalten bleibt. Wir erreichen dies, indem wir eine Liste von Tripeln finden, (i, j, k)
damit
sum of k*(13^i 19^j + 19^i 13^j) == 0 mod 16^20
wo 1 <= k <= 8
ist der Betrag, um den die Ziffer 1 erhöht werden muss (dh indem eine Ziffer von 2 auf 9 geändert wird - wir hätten 0 einschließen können, aber wir haben es nicht benötigt) und0 <= i < j < 600
sind Indexpaare.
Sobald wir die haben (i, j, k)
Drillinge, ändern wir die Ziffern auf (i, j)
und (j, i)
zu , 1+k
um die zweite Nummer. Die Drillinge wurden mit einem gierigen Backtracking-Algorithmus gefunden, und für die zweite Zahl über dem Ziffernquadrat sieht es folgendermaßen aus:
188181811111711 ...
815112111711111 ...
851611111111111 ...
116114118112111 ...
811115111111111 ...
121451111111111 ...
811111111111111 ...
111111111111111 ...
111811111111111 ...
171111111111111 ...
111111111111111 ...
111211111111111 ...
711111111111111 ...
111111111111111 ...
111111111111111 ...
............... .
............... .
............... .
Zum Beispiel (i, j, k) = (0, 1, 7)
entspricht das Ändern der Ziffern (0, 1)
(Position 600*0 + 1 = 1
) und (1, 0)
(Position 600*1 + 0 = 600
) zu 1 + 7 = 8
.
Hier ist der Backtracker in Python 3, obwohl eine genauere Betrachtung ergab, dass wir ziemlich viel Glück hatten, da tatsächlich kein Backtracking stattgefunden hat:
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
Als Bonus gibt es hier einen nicht so effizienten Port des Hashes in Python 3. Es war nutzlos.