P1306 斐波那契公约数

P1306 斐波那契公约数

斐波那契公约数

题目描述

对于 Fibonacci 数列:

$$ f_i = \begin{cases}
[i = 1] & i \leq 1 \
f_{i – 1} + f_{i – 2} & i \gt 1
\end{cases}$$

请求出 $f_n$ 与 $f_m$ 的最大公约数,即 $\gcd(f_n, f_m)$。

输入格式

一行两个正整数 $n$ 和 $m$ 。

输出格式

输出一行一个整数,代表 $f_n$ 和 $f_m$ 的最大公约数。答案请对 $10^8$ 取模。

样例 #1

样例输入 #1

4 7

样例输出 #1

1

提示

数据规模与约定

  • 对于 $100%$ 的数据,保证 $1 \leq n, m \leq 10^9$。

解题:

1. 传统 An = An-1 + An-2

An = An-1 + An-2 会超时

ll fb2(ll n)
{
    ll temp1, temp2, temp;
    // 第0项和第1项
    temp1 = 1;
    temp2 = 1;
    // 斐波那契数列
    for (unsigned long long i = 2; i <= n; i++)
    {
        temp = temp1 + temp2;
        temp1 = temp2;
        temp2 = temp;
        cout << temp2 << " ";
    }
    return temp2;
}

2. 矩阵乘法

chenfa

3. 快速倍增算法

  1. 快速倍增法简介

快速倍增法是一种高效计算斐波那契数列第 n 项的方法,其时间复杂度为 O(log n) 。该方法基于以下递推公式:
$$
\begin{cases}
F_{2k} = F_k \times [2F_{k+1} – F_k] \mod \text{MOD} \
F_{2k+1} = F_{k+1}^2 + F_k^2 \mod \text{MOD}
\end{cases}
$$
通过这些公式,可以将计算 ( F_n ) 的问题逐步拆分为更小的子问题,极大地减少了计算量。

递归实现:

#include <bits/stdc++.h>
using namespace std;
 
int a, b, c, d;
#define MOD 1000000007
 
// Function calculate the N-th fibonacci
// number using fast doubling method
void FastDoubling(int n, int res[])
{
    // Base Condition
    if (n == 0) {
        res[0] = 0;
        res[1] = 1;
        return;
    }
    FastDoubling((n / 2), res);
 
    // Here a = F(n)
    a = res[0];
 
    // Here b = F(n+1)
    b = res[1];
 
    c = 2 * b - a;
 
    if (c < 0)
        c += MOD;
 
    // As F(2n) = F(n)[2F(n+1) – F(n)]
    // Here c  = F(2n)
    c = (a * c) % MOD;
 
    // As F(2n + 1) = F(n)^2 + F(n+1)^2
    // Here d = F(2n + 1)
    d = (a * a + b * b) % MOD;
 
    // Check if N is 偶数还是奇数
    if (n % 2 == 0) {
        res[0] = c;
        res[1] = d;
    }
    else {
        res[0] = d;
        res[1] = c + d;
    }
}
 
// Driver code
int main()
{
    int N = 6;
    int res[2] = { 0 };
 
    FastDoubling(N, res);
 
    cout << res[0] << "\n";
    return 0;
}

迭代实现

// C++ program to find the Nth Fibonacci
// number using Fast Doubling Method iteratively
 
#include <bitset>
#include <iostream>
#include <string>
 
using namespace std;
 
// helper function to get binary string
string decimal_to_bin(int n)
{
    // use bitset to get binary string
    string bin = bitset<sizeof(int) * 8>(n).to_string();
    auto loc = bin.find('1');
    // remove leading zeros
    if (loc != string::npos)
        return bin.substr(loc);
    return "0";
}
 
// computes fib(n) iteratively using fast doubling method
long long fastfib(int n)
{
    string bin_of_n
        = decimal_to_bin(n); // binary string of n
 
    long long f[] = { 0, 1 }; // [F(i), F(i+1)] => i=0
 
    for (auto b : bin_of_n) {
        long long f2i1
            = f[1] * f[1] + f[0] * f[0]; // F(2i+1)
        long long f2i = f[0] * (2 * f[1] - f[0]); // F(2i)
 
        if (b == '0') {
            f[0] = f2i; // F(2i)
            f[1] = f2i1; // F(2i+1)
        }
        else {
            f[0] = f2i1; // F(2i+1)
            f[1] = f2i1 + f2i; // F(2i+2)
        }
    }
 
    return f[0];
}
 
int main()
{
    int n = 13;
    long long fib = fastfib(n);
    cout << "F(" << n << ") = " << fib << "\n";
}

直接使用位运算实现

#include <iostream>
#include <numeric> // 包含 std::gcd

using namespace std;

typedef unsigned long long ull;
typedef unsigned int uint;

const uint MOD = 100000000; // 1e8

// 结构体用于存储斐波那契数对 (F(k), F(k+1))
struct FibPair {
    uint Fk;   // F(k)
    uint Fk1;  // F(k+1)
};

// 迭代快速倍增法
FibPair fastDoubling(ull n) {
    FibPair result = {0, 1}; // 初始化 F(0) = 0, F(1) = 1
    ull current = n;

    // 找到最高位的 1
    int highestBit = 63 - __builtin_clzll(current);

    for (int i = highestBit; i >= 0; i--) {
        // 计算 F(2k) 和 F(2k+1)
        ull twoFkp1 = (2 * (ull)result.Fk1) % MOD;
        ull temp1 = (twoFkp1 + MOD - result.Fk) % MOD; // 2*F(k+1) - F(k) mod MOD
        uint F2k = ((ull)result.Fk * temp1) % MOD; // F(2k) mod MOD
        uint F2k1 = (((ull)result.Fk * result.Fk) % MOD + ((ull)result.Fk1 * result.Fk1) % MOD) % MOD; // F(2k+1) mod MOD

        // 更新 F(k) 和 F(k+1)
        result.Fk = F2k;
        result.Fk1 = F2k1;

        // 如果当前位是 1,则更新 F(k) 和 F(k+1) 为 F(2k+1) 和 F(2k+2)
        if ((current >> i) & 1) {
            uint temp = (result.Fk + result.Fk1) % MOD; // F(k+1) = F(k) + F(k+1) mod MOD
            result.Fk = result.Fk1;
            result.Fk1 = temp;
        }
    }

    return result;
}

int main()
{
    ull n, m;
    cin >> n >> m;

    // 计算 n 和 m 的最大公约数
    ull tempmax = gcd(n, m);

    // 如果 gcd(n, m) > 150000000,则取模 150000000
    if (tempmax > 150000000)
        tempmax = tempmax % 150000000;

    // 计算斐波那契数列的第 tempmax 项
    FibPair fibResult = fastDoubling(tempmax);

    // 输出 F(n) mod MOD
    cout << fibResult.Fk % MOD << endl;

    return 0;
}

暂无评论

发送评论 编辑评论

|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇