Быстрое вычисление чисел Фибоначчи

       Допустим нам необходимо вычислить n-ное число Фибоначчи быстрее, чем за линейное время. Представим вычисление следующего числа в виде матричного умножения:

(Fi Fi+1) * (0 1) = (Fi+1, Fi + Fi+1) = (Fi+1, Fi+2)

             1 1

Обозначим матрицу, для умножения чисел Фибоначчи за P.

       Заметим, что за одно умножение на матрицу P мы переходим на одно число Фибоначчи вперёд, поэтому умножив n-1 на матрицу P матрицу (F0 F1) мы получим Fn. Но умножение матриц ассоциативно поэтому мы можем просто возвести матрицу в степень, а это можно сделать за логарифмическое время.

       На самом деле данную технику можно применять к любым задачам, где члены последовательности линейно зависят от предыдущих.

 

Пример: Задача о трёх цветках. В саду посадили R красных, G зелёных и B синих цветов. Каждую ночь все цветы вянут, а на их месте вырастают новые. На месте одного красного вырастают r1 красных, r2 зелёных, r3 синих цветов (для других цветов также известны такие закономерности). Сколько цветов каждого цвета будет через N дней, N <= 10^18.

 

Факт. Предел отношения чисел Фибоначчи равен золотому сечению

 

const int mod = 1000000007; struct matrix {        int n, m;        vector<vector<ll> > v;          matrix(int n, int m): n(n), m(m) {                    v.resize(n, vector<ll>(m, 0));        }          vector<ll> & operator[] (int index) {                    return v[index];        }          vector<ll> operator[] (int index) const {                    return v[index];        }          matrix operator*(const matrix & b) const {                    matrix res(n, b.m);                    for (int i = 0; i < n; ++i) {                                for (int j = 0; j < b.m; ++j) {                                              for (int k = 0; k < m; ++k) {                                                        res[i][j] = (res[i][j] + v[i][k] * b[k][j] % mod) % mod;                                            }                                  }                    }                    return res;        }                    void print() {                    for (auto& i: v) {                                for (auto& j: i)                                            cout << j << ' ';                                cout << endl;                    }                    cout << endl;        } };   matrix binpow(const matrix & a, ll n) {        if (n == 1)                    return a;        if (n % 2 == 1)                    return a * binpow(a, n - 1);        matrix b = binpow(a, n / 2);        return b * b; } ... cin >> n; int n; matrix lst(1, 2), m(2, 2); lst.v = { { 0, 1 } }; m.v = { { 0, 1 },                    { 1, 1 } }; if (n <= 1) {        cout << lst.v[0][n];        return 0; } lst = lst * binpow(m, n - 1); cout << lst.v[0][1];

 

 




double arrow
Сейчас читают про: