洛谷 P1306 斐波那契公约数 题解

洛谷 P1306 斐波那契公约数 题解

洛谷 P1306 斐波那契公约数

题意

\(f\) 为斐波那契数列,求出 \(\gcd(f_n,f_m)\bmod10^8\)

\(1\le n,m\le10^9\)

思路

定理 \(\gcd(f_n,f_m)=f_{\gcd(n,m)}\)\(n,m>0\))。

引理 1 \(f_{n}=f_{m}f_{n-m+1}+f_{m-1}f_{n-m}\)

证明 根据斐波那契数列的递推式,有

\[\begin{align} &f_mf_{n-m+1}+f_{m-1}f_{n-m}\\ =&f_{m-1}(f_{n-m}+f_{n-m+1})+f_{m-2}f_{n-m+1}\nonumber\\ =&f_{m-1}f_{n-m+2}+f_{m-2}f_{n-m+1}. \end{align} \]

观察到 \((2)\)\((1)\) 结构相同,于是可以递推下去,直到 \((1)\)\(m=2\),于是 \((1)\) 等于

\[f_2f_{n-1}+f_1f_{n-2}=f_{n-1}+f_{n-2}=f_n.\kern{10pt}\square \]

引理 2(更相减损术) 设 \(a>b>0\),则 \(\gcd(a,b)=\gcd(a,a-b)\)

证明 见 3.2 L5-NOIP训练29 测试题解 - f2021ljh

由引理 2 也可以得到推论 \(\gcd(a,b)=\gcd(a,a-kb)\),其中 \(k\in\mathbb Z\)

引理 3 \(\gcd(f_m,f_{m-1})=1\)

证明 由递推式和引理 2 得

\[\gcd(f_m,f_{m-1})=\gcd(f_{m-1}+f_{m-2},f_{m-1})=\gcd(f_{m-1},f_{m-2}). \]

于是一直递推下去可以得到

\[\gcd(f_m,f_{m-1})=\gcd(f_2,f_1)=1.\kern{10pt}\square \]

下面证明整个定理。

证明 \(n=m\) 时显然成立。不妨设 \(n>m\)。由引理 1 和引理 2 的推论得

\[\begin{aligned} \gcd(f_n,f_m)&=\gcd(f_{m}f_{n-m+1}+f_{m-1}f_{n-m},f_m)\\ &=\gcd(f_{m-1}f_{n-m},f_m).\\ \end{aligned} \]

由引理 3 和 \(\gcd\) 的性质得

\[\gcd(f_n,f_m)=\gcd(f_{n-m},f_m). \]

继续递归下去,则有 \(\gcd(f_{n-m},f_m)=f_{\gcd(n-m,m)}\)(与更相减损术的递归方式相同)。于是原命题得证。\(\kern{10pt}\square\)

代码

/*
https://www.luogu.com.cn/problem/P1306
P1306 斐波那契公约数
*/

#include <cassert>
#include <iostream>
#include <algorithm>
#define f(x, y, z) for (int x = (y); x <= (z); ++x)
using namespace std;
typedef long long ll;
int constexpr MOD = 1e8;
int n, m;

inline int &AddEq(int &a, int const &b) { return (a += b) >= MOD ? (a -= MOD) : a; }
inline int Mul(int const &a, int const &b) { ll r = 1ll * a * b; return r >= MOD ? r % MOD : r; }

struct Matrix {
    int a[3][3], r, c;
} A, B, I, E;

Matrix operator*(Matrix const &a, Matrix const &b) {
    assert(a.c == b.r);
    Matrix c = E;
    c.r = a.r, c.c = b.c;
    f(i, 1, c.r) f(j, 1, c.c) f(k, 1, a.c)
        AddEq(c.a[i][j], Mul(a.a[i][k], b.a[k][j]));
    return c;
}

Matrix ksm(Matrix a, int x) {
    Matrix res = I;
    while (x) {
        if (x & 1) res = res * a;
        a = a * a;
        x >>= 1;
    }
    return res;
}

signed main() {
    ios::sync_with_stdio(false);
    cin.tie(0), cout.tie(0);
    
    cin >> n >> m;
    n = __gcd(n, m);
    if (n == 1 || n == 2) return cout << 1 << '\n', 0;
    I.r = I.c = 2, I.a[1][1] = I.a[2][2] = 1;
    A.r = 2, A.c = 1, A.a[1][1] = A.a[2][1] = 1;
    B.r = B.c = 2, B.a[1][1] = B.a[1][2] = B.a[2][1] = 1;
    A = ksm(B, n - 2) * A;
    cout << A.a[1][1] << '\n';
    
    return 0;
}
posted @ 2023-05-09 20:12  f2021ljh  阅读(65)  评论(0)    收藏  举报