Как найти выход при использовании чрезвычайно большого входа в этом алгоритме?

На собеседовании мне поставили следующую задачу:

Из следующей головоломки, каким будет результат головоломки (мощность (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
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
0
54
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Надеюсь, вы знаете, что такое матрицы и умножение матриц

Во всех точках состояние головоломки можно записать в виде вектора-столбца следующим образом:

[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])

Хм, очень проницательно. Мне, конечно, пришло в голову, что это как-то связано с возведением в степень матрицы (сначала я подумал о модульном возведении в степень), но да, это действительно было выше моего уровня знаний (студент 2-го курса компьютерной науки). Любопытно, что интервью проводилось для стандартной бэкэнд-работы на веб-сайте газеты, удивительно, что они подумали об этом вопросе (и да, вероятно, не связанном с повседневными задачами работы, лол). В любом случае, я безуспешно пытался закодировать другое решение после вашего ответа. Не стесняйтесь опубликовать реализацию, если вы подумали о какой-либо, все равно примете ваш ответ.

Lautaro Graciani 30.03.2023 01:19

@LautaroGraciani Я добавил простую реализацию. Он нашел ответ 2436815984. Что касается вопроса, то это антипаттерн. «Нам нужны умные люди. Я задам вопрос, на который могут ответить только умные люди!» Это выбирает для определенного типа людей, которые НЕ обязательно вам нужны.

btilly 30.03.2023 02:48

Другие вопросы по теме