斐波那契公约数(luogu 1306)

题目描述

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

Update:加入了一组数据。

输入输出格式

输入格式:

 

两个正整数n和m。(n,m<=10^9)

注意:数据很大

 

输出格式:

 

Fn和Fm的最大公约数。

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

 

输入输出样例

输入样例
4 7
输出样例
1

说明

用递归&递推会超时

用通项公式也会超时


 数据范围给的已经很明确,暴力肯定炸——因为这是道数学题嘛~

既然是数学,就少不了推公式

 

给定的是斐波那契数列第 n 和 m 项,我们设为 F(n) = a, F(n+1)=b。接下来:

F(n+2)=a+b

F(n+3)=a+2b

F(n+4)=2a+3b

……

可以发现:F(m)=F(m-n-1)*a+F(m-n)*b

 

我们要求的:

   gcd(Fn,Fm)

= gcd( F(n) , F(m-n-1)*a+F(m-n)*b )

= gcd( F(n) , F(m-n-1)*Fn+F(m-n)*F(n+1) )

这时候有一个引理:gcd(a,b)=gcd(a,b-a)  // 更相减损术原理

那我们就可以化简:

   gcd( F(n) , F(m-n-1)*F(n)+F(m-n)*F(n+1) )

= gcd( F(n) , F(m-n)*F(n+1) )

还有一个引理:gcd(n,n+1)=1  // 很显然的结论

所以继续可以化简:

   gcd( F(n) , F(m-n)*F(n+1) )

= gcd( F(n) , F(m-n) )  相当于  gcd( F(n) , F(m%n) )  

他们之间再互相取模,最后得到:gcd(F(0) , F(m,n) )

推论终于出来:gcd( F(n) , F(m) ) = F( gcd( n , m ) )

最后计算要用到矩阵乘法哦~详见博客

 

code

#include<stdio.h>
#include<string.h>
#include<algorithm>
#define ll long long 
using namespace std;
const int P=1e8;
struct node {
    ll mp[3][3];
    int h,l;
}p,ans;

int gcd(int x,int y)
{
    if(x<y) swap(x,y);
    if(x%y==0) return y;
    else return gcd(y,x%y);
}

node mul(node x,node y) {
    node tep;
    memset(&tep,0,sizeof(tep));
    for(int i=0;i<x.h;++i) 
        for(int j=0;j<y.l;++j) 
            for(int k=0;k<x.l;++k) 
                tep.mp[i][j]=(tep.mp[i][j]+x.mp[i][k]*y.mp[k][j])%P;
    tep.h=x.h,tep.l=y.l;
    return tep;
}

int juc(ll k)
{
    ans.mp[0][0]=ans.mp[0][1]=1;
    ans.h=1,ans.l=2;
    p.mp[0][0]=p.mp[0][1]=p.mp[1][0]=1;
    p.h=p.l=2;
    while(k) {
        if(k&1) ans=mul(ans,p);
        p=mul(p,p);
        k>>=1;
    }
    return ans.mp[0][0];
}

int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    int d=gcd(n,m);
    if(d<=2) printf("1");
    else printf("%d",juc(d-2));
    return 0;
}
从0到1很难,但从1到100很容易
原文地址:https://www.cnblogs.com/qseer/p/9744514.html