Быстрое вычисление членов линейной рекуррентной последовательности — различия между версиями
Dogzik (обсуждение | вклад) |
Dogzik (обсуждение | вклад) |
||
Строка 41: | Строка 41: | ||
# Возвести матрицу <tex>T</tex> в степень <tex>n</tex> | # Возвести матрицу <tex>T</tex> в степень <tex>n</tex> | ||
# Посчитать <tex>A_n</tex> как <tex>T^n \cdot A_0</tex> и взять из него <tex>a_n</tex> | # Посчитать <tex>A_n</tex> как <tex>T^n \cdot A_0</tex> и взять из него <tex>a_n</tex> | ||
+ | |||
+ | Используя быстрое возведения в степень второй пункт будет тратить <tex>O(k^3 \cdot logn)</tex> времени, умножение же в третьем пункте выполняется за <tex>O(k^2)</tex>. Итого мы получили алгоритм за <tex>O(k^3 \cdot logn)</tex>. |
Версия 19:00, 11 июня 2018
Пусть нам дана линейная реккурента размера . А именно: , а так же заданы первых членов. Требуется уметь вычислять произвольное .
Самый простой способ сделать это — последовательно считать каждый
, пока не сравняется с . Однако этот способ не самый эффективный, ведь он, очевидно, требует времени. Хочется уметь как-то быстрее решать эту задачу. Рассмотрим два способа это сделать.Первый способ (за )
Заметим, что линейные рекурренты хорошо выражаются через матрицы. Запишем наши первые
членов последовательности в столбик. Так же выпишем следующую матрицу перехода:Заметим, что умножив
слева на , мы получим столбик следующего вида: Аналогично, домножив слева на , получимПродолжая так для любого
, мы получим столбик , состоящий из подряд идущий членов последовательности, начиная с . Пользуясь ассоциативность произведения матриц, можно записать, что . Из этого соотношения вытекает алгоритм вычисления произвольного :- Инициализировать матрицы и
- Возвести матрицу в степень
- Посчитать как и взять из него
Используя быстрое возведения в степень второй пункт будет тратить
времени, умножение же в третьем пункте выполняется за . Итого мы получили алгоритм за .