题目
自己确定G1和G2,
G3=G1+G2,G4=G2+G3,
G[i]=G[i-1]+G[i-2],
对于给定n,如果n出现在这个数列中
求最小的G2,使得G1<=G2
输出G1和G2
思路来源
https://blog.youkuaiyun.com/Originum/article/details/81393168
题解
G1=a+0b,G2=0a+b,G3=a+b,G4=a+2b,G5=2a+3b
注意到它们的系数是在F数列中1 0 1 1 2 3 5 8出现的
Gi的a的系数是F[i-1],b的系数F[i],
而F序列后面是斐波那契数列
所以就递增扫F序列,判断F[i]x+F[i+1]y==n能否成立
先扩展欧几里得,由于令a<=b且b最小,
所以就是求x<=y的最小y,注意到y减小则x增大,
故y与x最接近,即下一步y减小x会反超
求出一组特解x,y后,令x和y最接近且x<=y的步骤如下
由于C++int除以int是近零取整,-2.5取整会被搞成-2,但是-3才符合条件
所以,如果这个值小于0且不能被整除,k--
然后x+=k*b/d,y-=k*a/d就是答案
心得
感觉思维题做的还是不够多,不知变通
这题根本看不出来是扩展欧几里得啊
还有算是知道了extgcd的一些小应用叭
代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
const int maxn=46;
int t,f[maxn]={1,0};//系数矩阵
ll c;
ll a,b,x,y,ansx,ansy;
ll extgcd(ll a,ll b,ll &x,ll &y)
{
ll d=a;
if(b)d=extgcd(b,a%b,y,x),y-=(a/b)*x;
else x=1,y=0;
return d;
}
int main()
{
for(int i=2;i<maxn;++i)
f[i]=f[i-1]+f[i-2];
scanf("%d",&t);
while(t--)
{
scanf("%lld",&c);
ansx=ansy=1e18;
for(int i=0;i<maxn-1;++i)
{
a=f[i];b=f[i+1];
//printf("%lld %lld\n",a,b);
ll d=extgcd(a,b,x,y);
if(c%d)continue;
x*=(c/d);y*=(c/d);
a/=d;b/=d;
ll k=(y-x)/(a+b);
if(x>y&&(y-x)%(a+b))k--;//近零取整,负的得-1
x+=k*b,y-=k*a;
if(x>0&&y>0&&y<ansy)
ansx=x,ansy=y;
}
printf("%lld %lld\n",ansx,ansy);
}
return 0;
}