[Luogu P1306] 斐波那契公约数

本文深入解析了Fibonacci数列中任意两项最大公约数的求解方法,通过数学推导揭示了一个关键结论:gcd(F[n], F[m]) = F[gcd(n, m)]。并介绍了如何利用矩阵快速幂算法实现高效计算。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

洛谷传送门

题目描述

对于Fibonacci数列: 1 , 1 , 2 , 3 , 5 , 8 , 13...... 1,1,2,3,5,8,13...... 1,1,2,3,5,8,13......大家应该很熟悉吧~~~但是现在有一个很“简单”问题:第 n n n项和第 m m m项的最大公约数是多少?

Update:加入了一组数据。

输入输出格式

输入格式:

两个正整数 n n n m m m。( n , m ≤ 1 0 9 n,m\le 10^9 n,m109

注意:数据很大

输出格式:

F n 和 F m F_n和F_m FnFm的最大公约数。

由于看了大数字就头晕,所以只要输出最后的 8 8 8位数字就可以了。

输入输出样例

输入样例#1:
4 7
输出样例#1:
1

说明

用递归&递推会超时

用通项公式也会超时

解题分析

做完这道题某数竞大佬才告诉我这是个常用结论qwq…

设不妨 m > n m>n m>n F [ n ] = a , F [ n + 1 ] = b F[n]=a,F[n+1]=b F[n]=a,F[n+1]=b, 那么
F [ m ] = F [ m − n − 1 ] × a + F [ m − n ] × b = F [ m − n − 1 ] × F [ n ] + F [ m − n ] × F [ n + 1 ] F[m]=F[m-n-1]\times a+F[m-n]\times b \\ =F[m-n-1]\times F[n]+F[m-n]\times F[n+1] F[m]=F[mn1]×a+F[mn]×b=F[mn1]×F[n]+F[mn]×F[n+1]
所以:
g c d ( F [ n ] , F [ m ] ) = g c d ( F [ n ] , F [ m − n ] × F [ n + 1 ] ) gcd(F[n],F[m])=gcd(F[n],F[m-n]\times F[n+1]) gcd(F[n],F[m])=gcd(F[n],F[mn]×F[n+1])
又因为
g c d ( F [ n ] , F [ n + 1 ] ) = g c d ( F [ n ] , F [ n ] + F [ n − 1 ] ) = g c d ( F [ n − 1 ] , F [ n ] ) = . . . = 1 gcd(F[n],F[n+1]) \\=gcd(F[n],F[n] + F[n-1]) \\= gcd(F[n-1],F[n]) \\=... \\=1 gcd(F[n],F[n+1])=gcd(F[n],F[n]+F[n1])=gcd(F[n1],F[n])=...=1
所以
g c d ( F [ n ] , F [ m ] ) = g c d ( F [ n ] , F [ m − n ] ) gcd(F[n],F[m])=gcd(F[n],F[m-n]) gcd(F[n],F[m])=gcd(F[n],F[mn])
如此递归下去即可得 g c d ( F [ n ] , F [ m ] ) = F [ g c d ( n , m ) ] gcd(F[n],F[m])=F[gcd(n,m)] gcd(F[n],F[m])=F[gcd(n,m)]

然后套个矩阵快速幂即可 A C AC AC

代码如下:

#include <cstdio>
#include <cstring>
#include <cctype>
#include <algorithm>
#include <cmath>
#include <cstdlib>
#define R register
#define IN inline
#define W while
#define gc getchar()
#define MOD 100000000
#define ll long long
struct Matrix
{
    ll mat[2][2];
    void clear() {memset(mat, 0, sizeof(mat));}
    void set_unit() {clear(); mat[0][0] = mat[1][1] = 1;}
};
IN Matrix operator * (const Matrix &x, const Matrix &y)
{
    Matrix ret; ret.clear();
    for (R int i = 0; i < 2; ++i)
    for (R int j = 0; j < 2; ++j)
    for (R int k = 0; k < 2; ++k)
    ret.mat[i][j] += x.mat[i][k] * y.mat[k][j];
    for (R int i = 0; i < 2; ++i)
    for (R int j = 0; j < 2; ++j)
    ret.mat[i][j] %= MOD;
    return ret;
}
IN Matrix fpow (R int tim)
{
    Matrix ret; ret.set_unit();
    Matrix mul = (Matrix){0, 1, 1, 1};
    W (tim)
    {
        if(tim & 1) ret = ret * mul;
        mul = mul * mul, tim >>= 1;
    }
    return ret;
}
int main(void)
{
    int n, m, temp;
    scanf("%d%d", &n, &m);
    temp = std::__gcd(n, m);
    if(temp <= 2) return puts("1"), 0;
    Matrix ini = (Matrix){1, 0, 1, 0};
    Matrix res = fpow(temp - 2);
    printf("%d", (res * ini).mat[1][0]);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值