给你一个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(' ') #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; } }