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

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/sugar_free_mint/article/details/82019289

题目

f ( 0 ) = a , f ( 1 ) = b , f ( n ) = f ( n 1 ) + f ( n 2 )

其中 a , b 均为正整数, n 2
问有多少种 ( a , b ) ,使得 k 出现在这个数列里,且不是前两项。


分析

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


代码

#include <cstdio>
#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);
}

猜你喜欢

转载自blog.csdn.net/sugar_free_mint/article/details/82019289