问题分析
我们稍微列一下式子就可以发现
因此,最笨的办法就是直接枚举a和b,这里
最大只有
,所以可以刚好卡过,但是不要傻傻的枚举,需要变换一下去枚举,去掉一层
#include<iostream>
#include<algorithm>
const int maxn=1e7;
using namespace std;
long f[50];
int main(){
int t,n;
f[1] = f[2] = 1;
for(int i = 3; ; ++i){
f[i] = f[i-1]+f[i-2];
if(f[i]>=(1e9+1)){
break;
}
}
cin>>t;
while(t--)
{
scanf("%d",&n);
int flag = 0;
for(int b = 1; b <= 1000000001; ++b){
for(int i = 2; i <= 45; ++i){
if(n<b*f[i]) break;
long a = (n-f[i]*b)/f[i-1];
if(a*f[i-1]+f[i]*b==n&&a>0&&a<=b){
printf("%d %d\n",a,b);
flag = 1;
break;
}
}
if(flag==1)
break;
}
}
return 0;
}
但是仔细看一下,泥萌木有发现这就是扩展欧里几得求最小的正整数
咩
首先
求出一组解,然后通过这组解去求最小正整数解。
#include <bits/stdc++.h>
using namespace std;
typedef long long LL;
void exgcd(LL a, LL b, LL &d, LL &x, LL &y)
{
if(!b) { d = a; x = 1; y = 0; }
else{
exgcd(b,a%b,d,y,x); y -= x*(a/b);
}
}
int f[46],t;
int main()
{
f[2] = f[1] = 1;
for(int i = 3; i < 46; ++i){
f[i] = f[i-1]+f[i-2];
}
cin>>t;
while(t--)
{
LL n;
cin>>n;
LL A = 1e9,B = 1e9;
for(int i = 3; i <= 45; ++i){
LL a = f[i-2], b = f[i-1], d, x, y;
exgcd(a,b,d,x,y);
if(n%d) continue;//判断是否有解
x *= n, y *= n;
a /= d, b /= d;
LL k = (y-x)/(a+b);//关键
x += k*b, y -= k*a;
if(x>y){
y += a;
x -= b;
}
if(x<=0||y<=0)
continue;
if(x<=y&&x<=A&&y<=B){
A = x;
B = y;
}
}
cout<<A<<' '<<B<<endl;
}
return 0;
}