zoukankan      html  css  js  c++  java
  • gcd步数

    题目描述

    一个有趣的函数F(a,b),表示对于数对(a,b)调用辗转相除法的步数为多少

    例如 (24,40)....0 (16,24).....1 (8,16).....2 (0,8)....3,即f(24,40)=3

    现在已知f(a,b)=k,求(a,b)使得a+b尽量小,同时,由于最终的(a,b)可能比较大,所以你只要在模10^9+7同余系下输出结果即可

    输入输出格式

    输入格式:

    一个数k

    输出格式:

    两个数a,b

    输入输出样例

    输入样例#1:
    1000000007
    输出样例#1:
    0 1000000006

    说明

    对于100% 数据 k < 10^15

    这个题很有意思,值得一想 

    我们需要考虑gcd的过程 

    最差情况是 -> 每次操作都是商1 -> 相当于两个数做差 

    这个时候就是次数最多,也就是我们要找的最小的a,b的情况

    由反复做差 -> 可以联想到斐波那契数列

    经过简单的举例, 

    这个题就是求斐波那契数列的第 k和k+1 项

    (上面不太懂的话自己举个例推算一下就很好理解了)

    由于数据范围很大,所以需要拿矩阵快速幂来算

    代码

    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #define MAXN 110
    #define mod 1000000007
    using namespace std;
    long long N,M;
    struct Matrix{
        long long mat[MAXN][MAXN];
        
        Matrix operator *(const Matrix& a)
        {
            Matrix c;
            memset(c.mat,0,sizeof c.mat);
            for(int i=1;i<=N;i++)
                for(int j=1;j<=N;j++)
                    for(int k=1;k<=N;k++)
                        c.mat[i][j]=(c.mat[i][j]+mat[i][k]*a.mat[k][j])%mod;
            return c;
        };
        
        Matrix operator ^(long long k)
        {
            Matrix c=*this,t=*this;
            k--;
            for(;k;k>>=1,t=t*t)
                if(k&1)c=c*t;
            return c;
        };
        
        void print()
        {
            for(int i=1;i<=N;i++)
            {
                for(int j=1;j<=N;j++)printf("%d ",mat[i][j]);
                printf("
    ");
            }
        };
        void scan()
        {
            for(int i=1;i<=N;i++)
                for(int j=1;j<=N;j++)
                    scanf("%lld",&mat[i][j]);
        };
    };
    
    int main()
    {
        scanf("%lld",&M);M++;
        if(M==2){printf("1 1
    ");return 0;}
        if(M>2)M-=1;
        else {printf("1");return 0;}
        Matrix x;
        N=2,x.mat[1][1]=1,x.mat[1][2]=1,x.mat[2][1]=1,x.mat[2][2]=0;
        Matrix p=x^M;
        printf("%lld ",p.mat[1][1]);
        p=x*p;
        printf("%lld
    ",p.mat[1][1]);
        return 0;
    }
  • 相关阅读:
    Luogu P3919【模板】可持久化数组(可持久化线段树/平衡树)
    线段树||BZOJ5194: [Usaco2018 Feb]Snow Boots||Luogu P4269 [USACO18FEB]Snow Boots G
    线段树||BZOJ1593: [Usaco2008 Feb]Hotel 旅馆||Luogu P2894 [USACO08FEB]酒店Hotel
    CF 610E. Alphabet Permutations
    BZOJ 1227: [SDOI2009]虔诚的墓主人
    BZOJ1009: [HNOI2008]GT考试
    BZOJ3674: 可持久化并查集加强版
    BZOJ3261: 最大异或和
    BZOJ2741: 【FOTILE模拟赛】L
    BZOJ3166: [Heoi2013]Alo
  • 原文地址:https://www.cnblogs.com/Elfish/p/7695113.html
Copyright © 2011-2022 走看看