숫자가 게시하기에 너무 커서 여기에 Pastebin에 있습니다 : num 1 , num 2 .
첫 번째 숫자는 숫자 600^2 = 360000
입니다. 두 번째 숫자는 다음 변경을 제외하고 동일합니다.
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
있습니다. 두 번째 숫자를 얻으려면 숫자의 일부를 변경하여 합계가 동일한 모듈러스가 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
.
파이썬 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
보너스를 들어, 여기 그것은 쓸모가 없었습니다 파이썬 3에 해시의 그리 효율적 포트.