На собеседовании мне поставили следующую задачу:
Из следующей головоломки, каким будет результат головоломки (мощность (2022, 100))?
function puzzle(N) {
A, B, C, D = 1, 1, 1, 1
.repeat N times {
X = D + 2 * C + 3 * B + 4 * A
a, b, c, d = b, c, d, x
}
return D % 10000000000
}
Изучив головоломку и реализовав ее на выбранном мной языке, я обнаружил, что она образует своего рода последовательность Фибоначчи. Однако код не закончил работу, поэтому я не смог найти результат. Я ответил, что код можно рефакторить как сумму выдумок для оптимизации вывода, но я не смог этого сделать, однако интервьюер сказал, что это правильные рассуждения в правильном направлении (он дал мне еще немного времени, чтобы взломать это, но я просто не удалось).
Теперь мне все еще любопытно, даже после того, как я подвел интервьюера. Могу ли я получить некоторое представление?
редактировать: благодаря принятому ответу я взломал решение на Python (кроме того, которое включено в обновление ответа), вот код, если кому-то интересно:
#reimplemented in python because Ruby is a real pain to work with matrices
def matrix_pow(matrix, power, modulus):
# Initialize result to the identity matrix of the same size as matrix
result = [[int(i == j) for j in range(len(matrix))] for i in range(len(matrix))]
while power > 0:
# If the current bit of the exponent is 1, multiply result by matrix
if power % 2 == 1:
result = matrix_multiply(result, matrix, modulus)
# Square matrix and divide power by 2
matrix = matrix_multiply(matrix, matrix, modulus)
power //= 2
# Return the result
return result
# This function multiplies two matrices modulo a given modulus
def matrix_multiply(matrix1, matrix2, modulus):
# Initialize result to a matrix of the appropriate size filled with zeros
result = [[0] * len(matrix2[0]) for _ in range(len(matrix1))]
# Perform matrix multiplication
for i in range(len(matrix1)):
for j in range(len(matrix2[0])):
for k in range(len(matrix2)):
result[i][j] += matrix1[i][k] * matrix2[k][j]
result[i][j] %= modulus
# Return the result
return result
# This function solves the puzzle
def puzzle(n):
# Initialize matrix M
M = [[0, 1, 0, 0],
[0, 0, 1, 0],
[0, 0, 0, 1],
[4, 3, 2, 1]]
# Calculate M^n modulo 10^10
M_pow = matrix_pow(M, n, 10**10)
# Initialize vector v
v = [1, 1, 1, 1]
# Multiply M^n by v to get the solution
result = matrix_multiply(M_pow, [[x] for x in v], 10**10)
# Return the element in the fourth row and first column of the result
return result[3][0]
print(puzzle(10))
# output 30520
print(puzzle(100))
# outputs 720820623
print(puzzle(2022**100))
# outputs 2436815984





Надеюсь, вы знаете, что такое матрицы и умножение матриц
Во всех точках состояние головоломки можно записать в виде вектора-столбца следующим образом:
[A]
[B]
[C]
[D]
После одного шага это может быть записано как:
[B] [0 1 0 0] [A]
[C] -- [0 0 1 0] / [B]
[D] -- [0 0 0 1] /\ [C]
[X] [4 3 2 1] [D]
Мы можем написать правую часть как M * v, где M — это матрица перехода 4x4, а v — вертикальный вектор.
После N шагов получаем M^N * v. Мы знаем наш начальный вектор v. И мы знаем, как подобрать ответ. Нам просто нужен хороший способ получить M^N.
И для этого, ну, есть хитрость. Озвучить сериал не сложно M, M^2, M^4, M^8, .... И с помощью этой серии и представления 2022^100 по основанию 2 вы можете найти ответ на загадку. К сожалению, цифры будут очень длинными. Но если вы сделаете все расчеты по модулю 10000000000 (это означает, что вы умножаете, а затем используете % 10000000000, чтобы получить остаток), то они остаются разумными, и вы можете получить ответ.
Связь с Фибоначчи заключается в том, что он вычисляется с помощью матрицы перехода 2x2, и вы можете использовать идентичную логику. Но я сомневаюсь, что есть способ перейти от Фибоначчи к этому.
Кстати, я считаю это забавной задачей, но не очень хорошим вопросом для интервью. Потому что произвольный навык, который он проверяет, не очень хорошо коррелирует с большей частью работы по программированию, которую вам, возможно, придется выполнять.
Вот версия Python. Я убедился, что это согласуется с наивным подходом для степеней до 100.
class ModuloValue:
def __init__ (self, n, m):
self.modulo = m
self.value = n % m
def __int__ (self):
return self.value
def __add__ (self, other):
return ModuloValue(self.value + int(other), self.modulo)
def __mul__ (self, other):
return ModuloValue(self.value * int(other), self.modulo)
def __str__ (self):
return str(self.value)
class Matrix:
def __init__ (self, rows):
self.rows = rows
def value (self, i, j):
return self.rows[i][j]
def __add__ (self, other):
rows1 = self.rows
rows2 = other.rows
rows_out = []
for i in range(len(rows1)):
row = []
for j in range(len(rows1[0])):
row.append(rows1[i][j] + rows2[i][j])
rows_out.append(row)
return Matrix(rows_out)
def __mul__ (self, other):
rows1 = self.rows
rows2 = other.rows
rows_out = []
for i in range(len(rows1)):
row = []
for k in range(len(rows2[0])):
value = rows1[i][0] * rows2[0][k]
for j in range(1, len(rows1[0])):
value = value + rows1[i][j] * rows2[j][k]
row.append(value)
rows_out.append(row)
return Matrix(rows_out)
def __str__ (self):
answer = '['
for row in self.rows:
answer += '\n [' + ', '.join((str(x) for x in row)) + ']'
return answer + '\n]'
def pow (self, n):
power = self
answer = None
while 0 < n:
if 1 == n % 2:
if answer is None:
answer = power
else:
answer = answer * power
power = power * power
n = n // 2
return answer
mod = 10000000000
rows = [
[0, 1, 0, 0],
[0, 0, 1, 0],
[0, 0, 0, 1],
[4, 3, 2, 1],
]
for i in range(len(rows)):
rows[i] = [ModuloValue(x, mod) for x in rows[i]]
m = Matrix(rows)
m_pow = m.pow(2022**100)
v = [[1], [1], [1], [1]]
print((m_pow * Matrix(v)).rows[3][0])
@LautaroGraciani Я добавил простую реализацию. Он нашел ответ 2436815984. Что касается вопроса, то это антипаттерн. «Нам нужны умные люди. Я задам вопрос, на который могут ответить только умные люди!» Это выбирает для определенного типа людей, которые НЕ обязательно вам нужны.
Хм, очень проницательно. Мне, конечно, пришло в голову, что это как-то связано с возведением в степень матрицы (сначала я подумал о модульном возведении в степень), но да, это действительно было выше моего уровня знаний (студент 2-го курса компьютерной науки). Любопытно, что интервью проводилось для стандартной бэкэнд-работы на веб-сайте газеты, удивительно, что они подумали об этом вопросе (и да, вероятно, не связанном с повседневными задачами работы, лол). В любом случае, я безуспешно пытался закодировать другое решение после вашего ответа. Не стесняйтесь опубликовать реализацию, если вы подумали о какой-либо, все равно примете ваш ответ.