Les chiffres sont trop gros pour être affichés, alors les voici sur Pastebin: num 1 , num 2 .
Le premier nombre est 600^2 = 360000
un. Le deuxième numéro est le même, à l'exception des modifications suivantes:
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
Les deux hachés 271088937720654725553339294593617693056
.
Explication
Jetons un coup d'œil à la première moitié du code:
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)
Donc, si nous pouvons trouver deux nombres d'entrée afin que les sommes de S[i][j]*13^i*19^j
soient le même modulo 16^20
pour le tableau initial de 600 et le tableau zippé, alors nous avons terminé.
Pour rendre les choses un peu plus faciles, nous ne considérerons que 600^2 = 360000
les nombres d'entrée à -digit, de sorte que le tableau de 600 de large ne soit que 600 par 600 carrés de chiffres. Cela rend les choses plus faciles à visualiser et est valable depuis 10^360000 ~ 2^(2^20.19) < 2^(2^30)
. Pour simplifier encore les choses, nous ne considérerons que ces chaînes d'entrée dont le carré des chiffres est symétrique le long de la diagonale principale, de sorte que le tableau d'origine et le tableau zippé sont les mêmes. Cela nous permet également d'ignorer l'inversion de chaîne initiale et la numérotation de droite à gauche, qui s'annulent mutuellement.
Pour commencer, nous pouvons considérer que le premier nombre est 360000
un. Pour obtenir le deuxième nombre, nous voulons le modifier en changeant certains des chiffres afin que les sommes soient les mêmes modulo 16^20
, tout en préservant la symétrie du carré des chiffres. Nous accomplissons cela en trouvant une liste de triplets (i, j, k)
afin que
sum of k*(13^i 19^j + 19^i 13^j) == 0 mod 16^20
où 1 <= k <= 8
est le montant pour augmenter le chiffre 1 (c.-à-d. passer à un chiffre de 2 à 9 - nous aurions pu inclure 0 mais nous n'en avions pas besoin) et 0 <= i < j < 600
sont des paires d'index.
Une fois que nous avons les (i, j, k)
triplés, nous changeons les chiffres à (i, j)
et (j, i)
pour 1+k
obtenir le deuxième numéro. Les triplets ont été trouvés en utilisant un algorithme de retour en arrière gourmand, et pour le deuxième nombre au-dessus du carré de chiffres ressemble à:
188181811111711 ...
815112111711111 ...
851611111111111 ...
116114118112111 ...
811115111111111 ...
121451111111111 ...
811111111111111 ...
111111111111111 ...
111811111111111 ...
171111111111111 ...
111111111111111 ...
111211111111111 ...
711111111111111 ...
111111111111111 ...
111111111111111 ...
............... .
............... .
............... .
Par exemple, (i, j, k) = (0, 1, 7)
correspond à la modification des chiffres (0, 1)
(position 600*0 + 1 = 1
) et (1, 0)
(position 600*1 + 0 = 600
) sur 1 + 7 = 8
.
Voici le backtracker dans Python 3, bien qu'une inspection plus approfondie ait révélé que nous avons été assez chanceux, car aucun retour en arrière ne s'est réellement produit:
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
Pour un bonus, voici un port moins efficace du hachage en Python 3. Il était inutile.