#扩展欧几里得算法#洛谷 3986 斐波那契数列

#题目
f ( 0 ) = a , f ( 1 ) = b , f ( n ) = f ( n − 1 ) + f ( n − 2 ) f(0)=a,f(1)=b,f(n)=f(n−1)+f(n−2) f(0)=a,f(1)=b,f(n)=f(n1)+f(n2)
其中 a , b a,b a,b均为正整数, n ≥ 2 。 n \geq 2。 n2
问有多少种 ( a , b ) (a, b) (a,b),使得 k k k出现在这个数列里,且不是前两项。


#分析
然而可以发现这个其实是ax+by=k的方案数,然而a和b可以通过斐波那契得到,关键是求方案数,那只要求出最小解,剩下就没了,搞搞细节就行了


#代码

#include 
#define mod 1000000007
using namespace std;
typedef long long ll;
ll f=1,g=0,k,ans;
ll gcd(ll a,ll b){return b?gcd(b,a%b):a;}
ll max(ll a,ll b){return (a>b)?a:b;}
ll exgcd(ll a,ll b,ll &x,ll &y){//扩展欧几里得
    if (!b) {x=1; y=0; return a;}
    else {
        ll k=exgcd(b,a%b,y,x);
        y-=a/b*x; return k;
    }
}
ll sum(ll x,ll y){return max(0,x%y?x/y:x/y-1);}
int main(){
    scanf("%lld",&k);
    for (register int i=1;i<=1000;i++){
        g+=f; ll x,y;
        if (f>k&&g>k) break;
        ll a=f,b=g;
        if (k%gcd(a,b)==0){
            ll t=k/exgcd(a,b,x,y);
            x*=t; y*=t;
            if (x<0||y<0){//存在负数
                if (x<0) ans=(ans+max(0,sum(y,a)+x/b))%mod;
                else ans=(ans+max(0,sum(x,b)+y/a))%mod;
            }
            else{
                if (x&&y) ans=(ans+sum(x,b)+sum(y,a)+1)%mod;
                else if (!x) ans=(ans+max(0,sum(y,a)))%mod;
                else ans=(ans+max(0,sum(x,b)))%mod;
            }
        }
        f^=g,g^=f,f^=g;
    }
    return !printf("%lld",ans);
}

你可能感兴趣的:(扩展欧几里得算法)