• 斐波那契公约数 【数论】


    题目

      洛谷 https://www.luogu.org/problemnew/show/P1306

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

    输入输出格式

      输入格式:

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

      注意:数据很大

      输出格式:

      Fn和Fm的最大公约数。

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

    分析  

      对于 gcd(F[n],F[m])  假令 n<m  F[n]=x ,F[n+1]=y;

      F[n+2]=x+y    =F[1]*x+F[2]*y
      F[n+3]=x+2*y      =F[2]*x+F[3]*y
      F[n+4]=2*x+3*y   =F[3]*x+F[4]*y
      ...
      F[m]=F[m-n-1]*x+F[m-n]*y 又F[n]=x;
      则Gcd(F[n],F[m])=Gcd(F[n],F[n+1]*F[m-n])

      又F[n+1]-F[n]=F[n-1]
      且Gcd(F[n+1],F[n]) =Gcd(F[n],F[n+1]-F[n]) (辗转相减法,辗转相除的变式)
                =Gcd(F[n],F[n-1])
                =Gcd(F[n-1],F[n-2]) (同理)
                =Gcd(F[3],F[2])=1;

      故Gcd(F[n],F[m])=Gcd(F[n],F[n+1]*F[m-n])=Gcd(F[n],F[m-n])
                          =Gcd(F[m-n],F[m-2*n]) (同理)
                          .....
                         =Gcd(F[Gcd(n,m)],F[Gcd(n,m)]) (辗转相减法的变形)
      得到Gcd(F[n],F[m])=F[Gcd(n,m)];

      对于F[Gcd(n,m)]的求解,运用矩阵快速幂优化(矩阵乘幂优化线性递推式)

    代码

     1 #include<queue>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<iostream>
     5 #include<algorithm>
     6 using namespace std;
     7 typedef long long ll;
     8 const int mod=100000000;
     9 int N,M;
    10 struct data{
    11     int r,c;
    12     ll a[3][3];
    13     data(){
    14         memset(a,0,sizeof(a));
    15     }
    16     friend data operator*(data a,data b){
    17         data c;
    18         c.r=a.r;c.c=b.c;
    19         for(int i=1;i<=a.r;i++)
    20         for(int k=1;k<=a.c;k++)
    21         for(int j=1;j<=b.c;j++)
    22          (c.a[i][j]+=a.a[i][k]*b.a[k][j])%=mod;
    23         return c;
    24     }
    25 };
    26 int Gcd(int x,int y){
    27     if(y==0) return x;
    28     return Gcd(y,x%y);
    29 }
    30 ll Fast(int t){
    31     data a,b,c;
    32     a.r=2,a.c=2;
    33     a.a[1][1]=1,a.a[1][2]=1,a.a[2][1]=1;
    34     b.r=2,b.c=1;
    35     b.a[1][1]=b.a[2][1]=1;
    36     while(t){
    37         if(t&1) b=a*b;
    38         a=a*a;
    39         t=t>>1;
    40     }
    41     return b.a[1][1];
    42 }
    43 int main(){
    44     scanf("%d%d",&N,&M);
    45     int t=Gcd(N,M);
    46     if(t<=2) cout<<1<<endl;
    47     else cout<<Fast(t-2);
    48     return 0;
    49 }
  • 相关阅读:
    最大团问题
    树的重心与相关性质
    2020年牛客算法入门课练习赛3 B
    牛客练习赛66 E
    浅谈后缀数组SA
    [随机化算法] 听天由命?浅谈Simulate Anneal模拟退火算法
    “优美的暴力”——树上启发式合并
    [线段树系列] LCT打延迟标记的正确姿势
    [Tarjan系列] Tarjan算法与有向图的SCC
    [Tarjan系列] 无向图e-DCC和v-DCC的缩点
  • 原文地址:https://www.cnblogs.com/Aloyd/p/9299283.html
Copyright © 2020-2023  润新知