洛谷 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)\)。
由引理 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;
}

浙公网安备 33010602011771号