フィボナッチ数列のO(logN)ソリューション

訪問へようこそ

フィボナッチ数列の時間の複雑さを\(O(\ log N)\)として見つける方法を紹介する前に最初に高速パワーを見てみましょう。

高速パワー

タイトルリンク

高速パワーは、数論における非常に基本的なアルゴリズムです。

\(a ^ b mod p、(1 \ le a、b、p \ le 10 ^ 9)\)を要求すると、単純なアプローチの場合、\(O(N)\)の時間の複雑さは明らかにタイムアウトします、そして高速パワーでできることは、時間の複雑さを\(O(\ log b)\)に減らすことです

練習

最初の前処理:\(a ^ {2 ^ 0}、a ^ {2 ^ 1}、a ^ {2 ^ 2}、a ^ {2 ^ 3}、...、a ^ {2 ^ { \ログb}} \)

各項を乗算して取得:\(a ^ {2 ^ 0 + 2 ^ 1 + 2 ^ 2 + 2 ^ 3 + ... + 2 ^ {\ log b}} \)

私たちは知っています:\(2 ^ 0 + 2 ^ 1 + 2 ^ 2 + 2 ^ 3 + ... + 2 ^ {\ log b} \)はバイナリ表現に変換できます:\(1111 ... 111 \)合計そこに\(\ログB + 1 \ ) 1

使用して(2 ^ I、0 \ \ルI \ル\ \ Bログ) 、それぞれが選択されCouchuを選択しないことができる\(\ 0) \(2 ^ {\ + Bログ1。} - 。1 \)は任意の整数。これには、構成したいものが含まれます:\(b \)

このステップの時間の複雑さは\(O(\ log b)\)です。

C ++コード

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

typedef long long LL;

int qmi(int a, int b, int p) {
    LL res = 1 % p;
    while (b) {
        if (b & 1) res =  res * a % p;
        b >>= 1;
        a = (LL)a * a % p;
    }
    return res;
}

int main() {
    int n;
    int a, b, p;
    scanf("%d", &n);
    while (n--) {
        scanf("%d%d%d", &a, &b, &p);
        printf("%lld\n", qmi(a, b, p));
    }
    return 0;
}

フィボナッチ数\(O(\ログN) \) を探して

まずフィボナッチ数列を見てください。

\ [f(n)= \ begin {cases} 1、&\ text {$ n = 1 $} \\\\ [2ex] 1、&\ text {$ n = 2 $} \\\\ [2ex] f(n-1)+ f(n-2)、&\ text {$ n \ ge 2 $} \ end {cases} \]

行ベクトル\(F_n = [f_n、f_ {n + 1}] \)を設定し、次に:

\(F_1 = [f_1、f_2] \)
\(F_2 = [f_2、f_3] \)

\(F_1 \ cdot A \)\(F_2 \)となるように行列\(A \)を作成する方法を見てみましょう

行列の乗算を知っている限り、構築するのは難しくありません。

\(A = \ begin {bmatrix} 0&1 \\ 1&1 \\ \ end {bmatrix} \)

したがって、\(F_2 = F1 \ cdot A \)\(F_3 = F2 \ cdot A \)、行列の乗算は連想則を満たすため、次のようになります。

\(F_n = F_1 \ underbrace {A \ cdot A \ cdots A} _ {\ text {n-1 times}} \)、即\(F_n = F_1 \ cdot A ^ {n-1} \)

したがって、高速のパワーを使用して検索できます。

C ++コード

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

typedef long long LL;

const int MOD = 1e9 + 7;

LL res[2] = {1LL, 1LL};
LL A[2][2] = {
    {0LL, 1LL},
    {1LL, 1LL}
};

void mul(LL c[2], LL a[2], LL b[][2]) {
    
    LL tmp[2] = {0};
    for (int i = 0; i < 2; i++) 
        for (int j = 0; j < 2; j++)
            tmp[i] = tmp[i] + (a[j] * b[j][i]) % MOD;
    
    memcpy(c, tmp, sizeof tmp);
}

void mul(LL c[][2], LL a[][2], LL b[][2]) {
    
    LL tmp[2][2] = {0};
    for (int i = 0; i < 2; i++)
        for (int j = 0; j < 2; j++)
            for (int k = 0; k < 2; k++)
                tmp[i][j] = tmp[i][j] + (a[i][k] * b[k][j]) % MOD;
    
    memcpy(c, tmp, sizeof tmp);
}

LL fib(int n) {
    
    n--;
    while (n) {
        if (n & 1) mul(res, res, A);
        n >>= 1;
        mul(A, A, A);
    }
    
    return res[0];
}


int main() {
    
    int n;
    scanf("%d", &n);
    
    printf("%lld", fib(n));
    
    return 0;
}

拡張子:フィボナッチと\(O(\ log n)\)の最初のn項を見つける

タイトルリンク

分析

上記と同様に、行ベクトルに\(S_n \)を追加します。

行ベクトル\(F_n = [f_n、f_ {n + 1}、S_n] \)を設定し、次に:

\(F_1 = [f_1、f_2、S_1] \)
\(F_2 = [f_2、f_3、S_2] \)

\(F_1 \ cdot A = F_2 \)となるような行列\(A \)を作成します。見つけるのは難しくありません。

\(A = \ begin {bmatrix} 0&1&0 \\\\ 1&1&1 \\\\ 0&0&1 \\\\ \ end {bmatrix} \)

C ++コード

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

typedef long long LL;

int n, m;

int res[3] = {1, 1, 1};
int A[3][3] = {
    {0, 1, 0},
    {1, 1, 1},
    {0, 0, 1}
};

void mul(int c[3], int a[3], int b[][3]) {
    
    int tmp[3] = {0};
    for (int i = 0; i < 3; i++)
        for (int j = 0; j < 3; j++)
            tmp[i] = (tmp[i] + (LL)a[j] * b[j][i]) % m;
    
    memcpy(c, tmp, sizeof tmp);
}

void mul(int c[][3], int a[][3], int b[][3]) {
    
    int tmp[3][3] = {0};
    for (int i = 0; i < 3; i++)
        for (int j = 0; j < 3; j++)
            for (int k = 0; k < 3; k++)
                tmp[i][j] = (tmp[i][j] + (LL)a[i][k] * b[k][j]) % m;
                
    memcpy(c, tmp, sizeof tmp);
}
 
int main() {
    
    scanf("%d%d", &n, &m);
    
    n--;
    while (n) {
        if (n & 1) mul(res, res, A);
        mul(A, A, A);
        n >>= 1;
    }
    
    printf("%d", res[2]);
    
    return 0;
}

参考資料

ブルーブリッジカップの
フィボナッチ数列を解決するいくつかの方法

おすすめ

転載: www.cnblogs.com/optimjie/p/12707530.html