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("\n"); } }; 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\n");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\n",p.mat[1][1]); return 0; }