洛谷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;
}
posted @ 2021-12-16 12:36  文艺平衡树  阅读(66)  评论(0编辑  收藏  举报