洛谷P3986 斐波那契數列
阿新 • • 發佈:2021-12-16
題目
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; }