洛谷P3986 斐波那契数列
题目
https://www.luogu.com.cn/problem/P3986
思路
首先,我们珂以用参数 \(a\) 和 \(b\) 把数列表示出来,数列有通项公式,不过本题貌似并不需要。
我们用数对 \((x_1,x_2)\) 来表示 \(x_1*a+x_2*b\)。
列举一下 \(f(n)\) 的前几项:\(f(0)=(1,0) , f(1)=(0,1) ,f(2)=(1,1) , f(3)=(1,2) , f(4)=(2,3)\)
明显的(也很好证),\(a\) 和 \(b\) 的系数就是斐波那契数列的相邻两项。令斐波那契数列第 \(n\) 项为 \(F(n)\) ,\(F(0)=0 , F(1)=1\)
则我们需要找到 \(a,b\) 使得 \(F(i)*a+F(i+1)*b=k (i\geq 1)\)
注意到\(x,y\)要求为正整数,所以 \(F(i)+F(i+1)\leq k\) 才能有正整数解, 符合条件的 \(i\) 不会很多,大致只需要解几十个不定方程,时间复杂度正确。
那么,对于一个不定方程,我们要统计正整数解的数量。将 \(x\) 根据其步长 \(\frac{lcm(F[i],F[i+1])}{F[i]}=F[i+1]\) 调整至最小的一个正值,此时 \(y\) 取到符合题设条件的最大值。
然后统计 \(y\) 在逐步减少的过程中能取到多少个正值就珂以了(此时 \(x\) 递增,保证满足正整数条件)。
注意边界条件,加一减一啥的判断。
代码
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#define ll long long
#define mod (int)(1e9+7)
using namespace std;
ll F[100];
ll exgcd(ll a,ll b, ll &x,ll &y){
ll g;
if(!a){
x=0;y=1;
return b;
}
g=exgcd(b%a,a,x,y);
ll t=x;
x=y-(b/a)*x;
y=t;
return g;
}
ll r(ll x,ll y){
if(x>0) return (x-1)/y;
else return x/y-1;
}
int main(){
int i,j;
ll k,x,y,g,ans,sum=0;
F[1]=1;
for(i=2;i<64;++i) F[i]=F[i-1]+F[i-2];
scanf("%lld",&k);
for(i=1;F[i+2]<=k;++i){
g=exgcd(F[i],F[i+1],x,y);
x*=k;y*=k;
ll t=r(x,F[i+1]);
x-=t*F[i+1];
y+=t*F[i];
if(y<=0) ans=0;
else ans=(y-1)/F[i]+1;
sum+=ans%mod;
sum%=mod;
}
printf("%lld",sum);
// system("pause");
return 0;
}