给你一个k,k是一个斐波那契数列的某一项,要你求出对应斐波那契数列的第1项a和第2项b,且a<=b,并且b在·所有情况下最小,a在b最小的情况下最小。
先讲一个斐波那契的特殊性质:
a3=b1*a1+b2*a2
a4=b2*a1+b3*a2
a5=b3*a1+b4*a2
a6=b4*a1+b5*a2
斐波那契数列可以这样写,所以每一项都可以认为是为由若干个a1和a2按一定比例相加得来,如果对数学稍微敏感一点,马上就可以看出系数b的值:
b1=1,b2=1,b3=2,b4=3,b5=5
由此发现决定a1a2比例的系数b实际上也是斐波那契数列
所以问题可以转化为:
求k=bx-1*a1+bx*a2的整数解(k为题目给出数,a1为a,a2为b)
这个式子看上去很像扩展欧几里得的式子,但是是不能用扩欧求解的,因为斐波那契数列邻项互质。(有兴趣可以自行推导)
所以我们对a2赋值从小到大求解即可。(因为第一要求是a2最小)
那么还有一个问题:
我们的系数第x项是如何确定的?
假设k=bx-1*a1+bx*a2我们已经遍历出答案了,a1a2为已知数,如果我们把系数下调会发生什么?
这里把bx拆分成bx-1和bx-2即可:
k=bx-2*a2+bx-1*(a1+a2)
很明显,a和b的值都变大了,所以可以得出结论:x越大越好,所以x值是递减遍历
代码这样写是因为写的时候是用的这个方程:
k-(a2-a1)*bx=a1(bx-1+bx)
附上代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<stack>
#include<map>
#include<vector>
#include<queue>
#include<set>
#include<iomanip>
#include<cctype>
#include<stack>
using namespace std;
const int MAXN=3e5+5;
const int INF=1<<30;
const long long mod=1e9+7;
const double eps=1e-8;
#define ll long long
#define edl putchar('\n')
#define sscc ios::sync_with_stdio(false);cin.tie(0);cout.tie(0);
#define FOR(i,a,b) for(int i=a;i<=b;i++)
#define ROF(i,a,b) for(int i=a;i>=b;i--)
#define FORLL(i,a,b) for(ll i=a;i<=b;i++)
#define ROFLL(i,a,b) for(ll i=a;i>=b;i--)
#define mst(a) memset(a,0,sizeof(a))
#define mstn(a,n) memset(a,n,sizeof(a))
#define zero(x)(((x)>0?(x):-(x))<eps)
int a[50],mina,minb,T,n,k,x,y;
int main()
{
a[1]=1,a[2]=1;
FOR(i,3,45)
a[i]=a[i-1]+a[i-2];
cin>>T;
while(T--)
{
minb=mina=mod;
cin>>n;
ROF(i,44,2)
{
x=0;
int m=n,k=a[i]+a[i-1];
while(m>0)
{
if(m%k==0)
{
mina=m/k,minb=mina+x;
break;
}
m-=a[i];
x++;
}
if(mina!=mod&&minb!=mod)
{
break;
}
}
cout<<mina<<" "<<minb<<endl;
}
}