这些数字太大而无法发布,因此这里是在Pastebin上:num 1,num 2。
第一个数字是600^2 = 360000
1。第二个数字是相同的,除了以下更改:
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
两者都散列为271088937720654725553339294593617693056
。
说明
让我们看一下代码的前半部分:
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)
因此,如果我们可以找到两个输入数字,以使初始的600宽数组和压缩数组的总和S[i][j]*13^i*19^j
具有相同的模16^20
,那么就可以了。
为了使操作更简单,我们将仅考虑- 600^2 = 360000
位输入数字,因此600宽的数组仅是600 x 600平方的数字。这使事情更容易可视化,并且从开始就有效10^360000 ~ 2^(2^20.19) < 2^(2^30)
。为了进一步简化,我们将仅考虑数字平方沿主对角线对称的输入字符串,以使原始数组和压缩数组相同。这也使我们可以忽略初始的字符串反转和从右到左的索引编号,它们相互抵消。
首先,我们可以将第一个数字设为360000
1。要获得第二个数字,我们想通过更改一些数字来修改此数字,以使总和具有相同的模数16^20
,同时保持数字平方的对称性。我们通过找到三元组列表来完成此操作,(i, j, k)
以便
sum of k*(13^i 19^j + 19^i 13^j) == 0 mod 16^20
其中1 <= k <= 8
将数字1增加的数量(即,将数字从2更改为9 –我们可以包括0,但我们不需要),并且0 <= i < j < 600
是索引对。
一旦我们有了(i, j, k)
三胞胎,我们改变了数字的(i, j)
和(j, i)
以1+k
获得第二个数字。使用贪婪的回溯算法找到了三元组,数字正方形上方的第二个数字如下所示:
188181811111711 ...
815112111711111 ...
851611111111111 ...
116114118112111 ...
811115111111111 ...
121451111111111 ...
811111111111111 ...
111111111111111 ...
111811111111111 ...
171111111111111 ...
111111111111111 ...
111211111111111 ...
711111111111111 ...
111111111111111 ...
111111111111111 ...
............... .
............... .
............... .
例如,(i, j, k) = (0, 1, 7)
对应于将数字(0, 1)
(position 600*0 + 1 = 1
)和(1, 0)
(position 600*1 + 0 = 600
)更改为1 + 7 = 8
。
这是Python 3中的回溯器,尽管仔细检查发现我们很幸运,因为实际上没有发生回溯:
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
对于奖金,这里是在Python 3这是无用的散列的不那么高效的口岸。