1. 程式人生 > 其它 >洛谷P3986 斐波那契數列

洛谷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;
}