P3986 斐波那契数列
定义一个数列: f ( 1 ) = a , f ( 2 ) = b , f ( n ( n > 1 ) ) = f ( n − 1 ) + f ( n − 2 ) f(1)=a,f(2)=b,f(n\:(n>1)\:)=f(n-1)+f(n-2) f(1)=a,f(2)=b,f(n(n>1))=f(n−1)+f(n−2),其中 a , b a,b a,b均为正整数,问有多少种 ( a , b ) (a,b) (a,b)使得 K K K出现在数列中且不是前两项.
输出需要 m o d 1 e 9 + 7 mod \:1e9+7 mod1e9+7.
我们由题目条件可以得到若干个等式
f j + f j + 1 = K ( j > = 0 ) f_j+f_{j+1}=K(j>=0) fj+fj+1=K(j>=0)
我们要求的就是使得上面这个等式被满足的 f 0 , f 1 f_0,f_1 f0,f1的数量.
斐波那契数列:
由斐波那契数列的矩阵形式我们可以知道,斐波那契数列的第 i i i项可以如是表示
[ f n f n − 1 ] ∗ [ 1 1 1 0 ] = [ f n + 1 f n ] \begin{bmatrix} f_n\ f_{n-1}\ \end{bmatrix}*\begin{bmatrix} 1 & 1\\ 1 & 0 \end{bmatrix}=\begin{bmatrix} f_{n+1}\ f_n\ \end{bmatrix} [fn fn−1 ]∗[1110]=[fn+1 fn ]
也就是
[ f 1 f 0 ] ∗ [ 1 1 1 0 ] n − 1 = [ f n f n − 1 ] \begin{bmatrix} f_1\ f_{0}\ \end{bmatrix}*\begin{bmatrix} 1 & 1\\ 1 & 0 \end{bmatrix}^{n-1}=\begin{bmatrix} f_{n}\ f_{n-1}\ \end{bmatrix} [f1 f0 ]∗[1110]n−1=[fn fn−1 ]
也就是说,斐波那契数列的第 i i i项只与第0项和第1项有关,设 f 0 = 1 , f 1 = 1 f_0=1,f_1=1 f0=1,f1=1的斐波那契数列第 i i i项为 f i f_i fi, f 0 = a , f 1 = b f_0=a,f_1=b f0=a,f1=b的斐波那契数列第 i i i项为 g i g_i gi,那么我们可以得到
g i = f i − 2 ∗ a + f i − 1 ∗ b g_i=f_{i-2}*a+f_{i-1}*b gi=fi−2∗a+fi−1∗b
现在,问题就转化成了求满足不定方程 K = f i − 2 ∗ a + f i − 1 ∗ b K=f_{i-2}*a+f_{i-1}*b K=fi−2∗a+fi−1∗b的方案数.
首先发现 f i − 1 , f i − 2 f_{i-1},f_{i-2} fi−1,fi−2发现这个东西显然可以枚举,因为斐波那契数列小于等于 1 e 9 1e9 1e9的项只有大约 40 40 40项左右.
那么我们就枚举斐波那契数列的第 i ( i < = 40 ) i(i<=40) i(i<=40)项,然后对于构成的不定方程分别求合法方案数即可.
求不定方程的特殊解:要求不定方程的合法解,首先要求出不定方程的一组通解.
我们有一个结论:斐波那契数列的任相邻两项都是互质的(窝不会证)
所以对于每一个不定方程 K = f i − 2 ∗ a + f i − 1 ∗ b K=f_{i-2}*a+f_{i-1}*b K=fi−2∗a+fi−1∗b,都一定能求出通解 ( a 1 , b 1 ) (a_1,b_1) (a1,b1).
实际上就算不知道这个结论,在程序里多写一个特判同样没有问题.
不定方程的通解怎么求?当然是用拓展欧几里得.
设 A = f i − 2 , B = f i − 1 , X = a , Y = b A=f_{i-2},B=f_{i-1},X=a,Y=b A=fi−2,B=fi−1,X=a,Y=b ,我们要做的就是先求出不定方程 1 = A X + B Y 1=AX+BY 1=AX+BY的一组解 ( X , Y ) (X,Y) (X,Y),那么 a , b a,b a,b的一组特殊解 ( a 1 , b 1 ) = ( K ∗ X , K ∗ Y ) (a_1,b_1)=(K*X,K*Y) (a1,b1)=(K∗X,K∗Y)
关于不定方程的一组解:假设我们求出了不定方程 a x + b y = g c d ( a , b ) ax+by=gcd(a,b) ax+by=gcd(a,b)的一组解 ( x 1 , y 1 ) (x_1,y_1) (x1,y1),
那么对于一个不定方程 a x + b y = K , K ∣ g c d ( a , b ) ax+by=K,K|gcd(a,b) ax+by=K,K∣gcd(a,b),设 w = K / g c d ( a , b ) w=K/gcd(a,b) w=K/gcd(a,b),那么这个不定方程同样有一组解 ( x 1 ∗ w , x 2 ∗ w ) (x_1*w,x_2*w) (x1∗w,x2∗w)
求不定方程通解&通解数量:求出了一组解之后,我们要做的就是求出通解的表示方式. 而要求这个表示方式,自然就要先求通解间隔.
我们现在求出了不定方程 a x + b y = k ax+by=k ax+by=k的一组特殊解 ( x 1 , y 1 ) (x_1,y_1) (x1,y1).
假设对于 x x x的通解间隔为 p p p,对于 y y y的通解间隔为 q q q,那么我们显然有
a ( x 1 + p ) + b ( y 1 + q ) = k a(x_1+p)+b(y_1+q)=k a(x1+p)+b(y1+q)=k
联立 a x 1 + b y 1 = k ax_1+by_1=k ax1+by1=k得
a p = − b q ap=-bq ap=−bq
也就是
p = − b a ∗ q p=-\frac{b}{a}*q p=−ab∗q
由于 p , q p,q p,q都是整数, g c d ( a , b ) = 1 gcd(a,b)=1 gcd(a,b)=1,所以对于 y y y的最小通解间隔为 q = a q=a q=a.
同理对于 x x x的最小通解间隔为 p = b p=b p=b
也就是对于以上的不定方程, ( x 1 + b n , y 1 − a n ) (x_1+bn,y_1-an) (x1+bn,y1−an)也是一组解(简记为“一减一加”).
对应在题目中, ( K ∗ X + f n − 2 ∗ n , K ∗ Y − f n − 1 ∗ n ) (K*X+f_{n-2}*n,K*Y-f_{n-1}*n) (K∗X+fn−2∗n,K∗Y−fn−1∗n)也是一组解.
而对于一组解 ( x , y ) (x,y) (x,y), x , y x,y x,y都要大于0(题目要求的正整数的条件). 我们只需要求出满足 ( x , y ) (x,y) (x,y)大于0的解的数量即可.
到这里整道题就做完了. 不要忘记取模.
另外,有没有可能出现同样的解 ( a , b ) (a,b) (a,b)出现了两次的情况呢?答案是否定的,因为这需要
a f i + b f i − 1 = a f j + b f j − 1 , i ! = j af_i+bf_{i-1}=af_j+bf_{j-1},i!=j afi+bfi−1=afj+bfj−1,i!=j
由于斐波那契数列任两项不相等,所以以上式子是不成立的.
#include
#define ll long long
using namespace std;
const ll mod=1e9+7;
ll n,gcd,x,y,f[60],ans;
ll exgcd(ll a,ll b){
if(!b){
x=1,y=0;
return a;
}
ll ret=exgcd(b,a%b);
ll z=x;x=y;y=z-a/b*y;
return ret;
}//求对于每个不定方程的特殊解
int main(){
scanf("%lld",&n);
f[0]=1,f[1]=1;
for(int i=2;i<=50;i++){
f[i]=f[i-1]+f[i-2];
} //K不会超过斐波那契数列第40项
for(int i=1;f[i]<n;i++){
gcd=exgcd(f[i-1],f[i]);
x*=n,y*=n;
if(x<=0){
ll dex=-x/f[i]+1;
x+=dex*f[i],y-=dex*f[i-1];//(x,y)要一起进退
}//如果x<=0,把它加到大于0为止
if(y<=0){
ll dex=-y/f[i-1]+1;
y+=dex*f[i-1],x-=dex*f[i];
}//同理
if(x<=0||y<=0)continue;//如果处理之后仍然找不到解,说明无解
ans+=(y%f[i-1]==0)?y/f[i-1]:y/f[i-1]+1;
//加上最多能取的数量(减多少减到0,由于这边减,另外一边是加,所以另外一边不用管)
ans%=mod;
ans+=(x%f[i]==0)?x/f[i]-1:x/f[i];//注意判断整除的情况
ans%=mod;
}
printf("%lld\n",ans);
return 0;
}