Các con số quá lớn để đăng, vì vậy ở đây chúng nằm trên Pastebin: num 1 , num 2 .
Số đầu tiên là số 600^2 = 360000
. Số thứ hai là như nhau, ngoại trừ các thay đổi sau:
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
Cả băm để 271088937720654725553339294593617693056
.
Giải trình
Chúng ta hãy xem nửa đầu của 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)
Vì vậy, nếu chúng ta có thể tìm thấy hai số đầu vào sao cho tổng của S[i][j]*13^i*19^j
cùng một modulo 16^20
cho cả mảng rộng 600 ban đầu và mảng được nén, thì chúng ta đã hoàn thành.
Để làm cho mọi thứ dễ dàng hơn một chút, chúng tôi sẽ chỉ xem xét các 600^2 = 360000
số đầu vào kỹ thuật số, sao cho mảng rộng 600 chỉ là một chữ số 600 x 600 vuông. Điều này làm cho mọi thứ dễ hình dung hơn và có giá trị vì10^360000 ~ 2^(2^20.19) < 2^(2^30)
. Để đơn giản hóa mọi thứ hơn nữa, chúng ta sẽ chỉ xem xét các chuỗi đầu vào như vậy có hình vuông chữ số đối xứng dọc theo đường chéo chính, sao cho mảng ban đầu và mảng được nén là như nhau. Điều này cũng cho phép chúng ta bỏ qua việc đảo ngược chuỗi ban đầu và đánh số chỉ mục từ phải sang trái, chúng sẽ triệt tiêu lẫn nhau.
Để bắt đầu, chúng tôi có thể lấy số đầu tiên là số đầu tiên 360000
. Để có được số thứ hai, chúng tôi muốn sửa đổi điều này bằng cách thay đổi một số chữ số sao cho các tổng là cùng một modulo 16^20
, trong khi vẫn giữ đối xứng của hình vuông chữ số. Chúng tôi thực hiện điều này bằng cách tìm một danh sách các bộ ba (i, j, k)
để
sum of k*(13^i 19^j + 19^i 13^j) == 0 mod 16^20
trong đó 1 <= k <= 8
số tiền để tăng chữ số 1 bằng (tức là thay đổi thành chữ số từ 2 lên 9 - chúng tôi có thể đã bao gồm 0 nhưng chúng tôi không cần nó) và 0 <= i < j < 600
là cặp chỉ số.
Một khi chúng ta có (i, j, k)
ba, chúng ta thay đổi các chữ số tại (i, j)
và (j, i)
để 1+k
để có được số thứ hai. Các bộ ba được tìm thấy bằng thuật toán quay lui tham lam và cho số thứ hai phía trên hình vuông chữ số trông như sau:
188181811111711 ...
815112111711111 ...
851611111111111 ...
116114118112111 ...
811115111111111 ...
121451111111111 ...
811111111111111 ...
111111111111111 ...
111811111111111 ...
171111111111111 ...
111111111111111 ...
111211111111111 ...
711111111111111 ...
111111111111111 ...
111111111111111 ...
............... .
............... .
............... .
Ví dụ, (i, j, k) = (0, 1, 7)
tương ứng với việc thay đổi các chữ số (0, 1)
(vị trí 600*0 + 1 = 1
) và (1, 0)
(vị trí 600*1 + 0 = 600
) thành 1 + 7 = 8
.
Đây là trình quay lại trong Python 3, mặc dù kiểm tra kỹ hơn cho thấy chúng tôi khá may mắn, vì thực tế không có quay lại nào xảy ra:
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
Đối với phần thưởng, đây là một cổng băm không hiệu quả trong Python 3. Nó vô dụng.