Быстрое вычисление членов линейной рекуррентной последовательности — различия между версиями
Dogzik (обсуждение | вклад) |
Dogzik (обсуждение | вклад) |
||
Строка 1: | Строка 1: | ||
− | Пусть нам дана [[Теорема о связи между рациональностью производящей функции и линейной рекуррентностью задаваемой ей последовательности#def_linear.|линейная реккурента]] размера <tex>k</tex>. А именно: <tex>a_n = c_1 \cdot a_{n - 1} + c_2 \cdot a_{n - 2} + \cdots + c_k \cdot a_{n - k}</tex>, а так же заданы <tex>k</tex> первых членов. Требуется уметь вычислять произвольное <tex>a_n</tex>. | + | Пусть нам дана [[Теорема о связи между рациональностью производящей функции и линейной рекуррентностью задаваемой ей последовательности#def_linear.|линейная реккурента]] размера <tex>k</tex>. А именно: <tex>a_n = c_1 \cdot a_{n - 1} + c_2 \cdot a_{n - 2} + \cdots + c_k \cdot a_{n - k}</tex>, а так же заданы <tex>k</tex> первых членов последовательности. Требуется уметь вычислять произвольное <tex>a_n</tex>. |
Самый простой способ сделать это {{---}} последовательно считать каждый <tex>a_i</tex>, пока <tex>i</tex> не сравняется с <tex>n</tex>. Однако этот способ не самый эффективный, ведь он, очевидно, требует <tex>O(n \cdot k)</tex> времени. Хочется уметь как-то быстрее решать эту задачу. Рассмотрим два способа это сделать. | Самый простой способ сделать это {{---}} последовательно считать каждый <tex>a_i</tex>, пока <tex>i</tex> не сравняется с <tex>n</tex>. Однако этот способ не самый эффективный, ведь он, очевидно, требует <tex>O(n \cdot k)</tex> времени. Хочется уметь как-то быстрее решать эту задачу. Рассмотрим два способа это сделать. |
Версия 19:01, 11 июня 2018
Пусть нам дана линейная реккурента размера . А именно: , а так же заданы первых членов последовательности. Требуется уметь вычислять произвольное .
Самый простой способ сделать это — последовательно считать каждый
, пока не сравняется с . Однако этот способ не самый эффективный, ведь он, очевидно, требует времени. Хочется уметь как-то быстрее решать эту задачу. Рассмотрим два способа это сделать.Первый способ (за )
Заметим, что линейные рекурренты хорошо выражаются через матрицы. Запишем наши первые
членов последовательности в столбик. Так же выпишем следующую матрицу перехода:Заметим, что умножив
слева на , мы получим столбик следующего вида: Аналогично, домножив слева на , получимПродолжая так для любого
, мы получим столбик , состоящий из подряд идущий членов последовательности, начиная с . Пользуясь ассоциативность произведения матриц, можно записать, что . Из этого соотношения вытекает алгоритм вычисления произвольного :- Инициализировать матрицы и
- Возвести матрицу в степень
- Посчитать как и взять из него
Используя быстрое возведения в степень второй пункт будет тратить
времени, умножение же в третьем пункте выполняется за . Итого мы получили алгоритм за .