Interesting Integers

给你一个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;
	}
}

  

posted @ 2018-07-11 16:24  诚信肥宅  阅读(140)  评论(0编辑  收藏  举报