Sayılar gönderilemeyecek kadar büyük, bu yüzden burada Pastebin'de: num 1 , num 2 .
İlk sayı 600^2 = 360000
olanlardır. İkinci sayı, aşağıdaki değişiklikler dışında aynıdır:
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
Her ikisi de karma 271088937720654725553339294593617693056
.
açıklama
Kodun ilk yarısına bir göz atalım:
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)
Yani iki giriş numarası bulabilirsek, S[i][j]*13^i*19^j
16^20
600 genişlikli dizi ve sıkıştırılmış dizi aynı modülo olur , işimiz biter.
İşleri biraz daha kolaylaştırmak için, yalnızca 600^2 = 360000
-digit giriş sayılarını dikkate alacağız, böylece 600 genişlikli dizi sadece 600 x 600 basamaklı bir rakam olacak. Bu, görselleştirmeyi kolaylaştırır ve10^360000 ~ 2^(2^20.19) < 2^(2^30)
. İşleri daha da basitleştirmek için, yalnızca basamak karesi ana diyagonal boyunca simetrik olan bu tür giriş dizelerini dikkate alacağız, böylece orijinal dizi ve sıkıştırılmış dizi aynıdır. Bu aynı zamanda, ilk dize tersini ve birbirini iptal eden sağdan sola dizin numaralandırmasını yok saymamızı sağlar.
Bizi başlatmak için ilk numara 360000
olanları alabiliriz. İkinci sayıyı elde etmek için, rakamların bazılarını değiştirerek 16^20
rakamların karesinin simetrisini korurken toplamların aynı modülo olmasını sağlayarak değiştirmek istiyoruz . Bunu üçlü bir liste bularak başarıyoruz, (i, j, k)
böylece
sum of k*(13^i 19^j + 19^i 13^j) == 0 mod 16^20
Nerede 1 <= k <= 8
tarafından haneyi 1 arttırmak miktarıdır (yani 2 ila 9 arasında bir rakam değişen - biz 0 dahil olabilirdi ama biz gerek yoktu) ve 0 <= i < j < 600
endeks çiftleri vardır.
Elimizdeki kez (i, j, k)
üçüz, biz az hane değiştirmek (i, j)
ve (j, i)
için 1+k
ikinci sayı elde etmek. Üçüzler, açgözlü bir geri izleme algoritması kullanılarak bulundu ve basamak karesinin üzerindeki ikinci sayı için şöyle görünüyor:
188181811111711 ...
815112111711111 ...
851611111111111 ...
116114118112111 ...
811115111111111 ...
121451111111111 ...
811111111111111 ...
111111111111111 ...
111811111111111 ...
171111111111111 ...
111111111111111 ...
111211111111111 ...
711111111111111 ...
111111111111111 ...
111111111111111 ...
............... .
............... .
............... .
Örneğin (i, j, k) = (0, 1, 7)
, rakamların (0, 1)
(konum 600*0 + 1 = 1
) ve (1, 0)
(konum 600*1 + 0 = 600
) ' un değiştirilmesine karşılık gelir 1 + 7 = 8
.
Python 3'teki backtracker, daha yakından inceleme, aslında hiç geri izleme olmadığı için oldukça şanslı olduğumuzu ortaya koymasına rağmen:
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
Bir bonus için, burada Python 3'teki karma'nın çok verimli olmayan bir limanı.