• 斐波那契公约数(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很容易
  • 相关阅读:
    springboot maven
    基于spring http服务远程调用
    java注解
    mongdob-高可用集群
    Mongodb学习笔记--分片集群
    Mongodb学习笔记--springboot中使用mongodb
    Mongodb学习笔记--用户和权限
    Mongodb学习笔记--使用java连接操作mongodb
    mongodb学习笔记--集群配置(二)-副本集配置
    mongodb学习笔记--集群配置(一)
  • 原文地址:https://www.cnblogs.com/qseer/p/9744514.html
Copyright © 2020-2023  润新知