https://cn.vjudge.net/contest/322620#problem/I
t组输入,给定一个数n,求出最小的a,b (a<b),使得以a,b为开头的斐波那契数列包含n
两个斐波那契数列的和也是斐波那契数列
先写出两个以 1,0 和0,1开头的数列
a[ ] = 1,0,1,2,3,5,8,13,21,34,55
b[ ] = 0,1,1,2,3,5,8,13,21,34,55
若 x*a[ ]+y*b[ ]中包含n,则求出的a,b为x,y
从后往前(因为尽可能的找到a,b最小,那么n一定是尽可能的靠后),
对于每一对a[ i ],b[ i ],求a[ i ]*x +b[ i ]*y = n的 关于y的最小整数解(x,y必须大于0&&x<y),
#include<bits/stdc++.h>
using namespace std;
long long a[60],b[60];
void init()//求出两个单位序列
{
a[0] = b[1] = 1;
b[0] = a[1] = 0;
for(long long i = 2; i <= 56; i ++)
{
a[i] = a[i-1]+a[i-2];
b[i] = b[i-1]+b[i-2];
}
}
long long ex_gcd(long long a, long long b, long long &x, long long &y)//扩展欧几里得求解
{
if(b == 0)
{
long long g = a;
x = 1;
y = 0;
return g;
}
else
{
long long g = ex_gcd(b,a%b,x,y);
long long x1 = y,y1 = x-a/b*y;
x = x1;
y = y1;
return g;
}
}
int main()
{
init();
long long i,j,m,n,t,x,y,num;
scanf("%lld",&t);
while(t --)
{
scanf("%lld",&n);
for(i = 55; i >= 2; i --)//从后往前找
{
if(a[i]+b[i]<= n)//可能有正整数解的条件
{
if(n%__gcd(a[i],b[i]) == 0)//有解的条件
{
long long g = ex_gcd(a[i],b[i],x,y);
num = n/g;
x*= num;
y*= num;//此时得到了a[ i ]*x +b[ i ]*y = n的一组解
if(y < x)//接下来通过对x,y的加减,使得y>=x&&y最小
{
//y+a*k >= x -b*k
long long k = (x-y)/(a[i]+b[i]);
if(y+a[i]*k < x -b[i]*k)
k++;
x -= b[i]*k;
y+= a[i]*k;
}
else
{
//y-a*k >= x+b*k
long long k = (y-x)/(a[i]+b[i]);
if(y-a[i]*k < x+b[i]*k)
k++;
x += b[i]*k;
y -= a[i]*k;
}
if(x <=0||y<= 0)
continue;
printf("%lld %lld\n",x,y);
break;
}
}
}
}
return 0;
}