P3986 斐波那契数列——数学(EXGCD)

https://www.luogu.org/problem/P3986

很久很久以前,我好像写过exgcd,但是我已经忘了;

洛谷上搜EXGCD搜不到,要搜(扩展欧几里得)

这道题就是ax+by=k,其中ab为斐波那契数列里面相邻的两项;

a+b=k ;a+2b=k;2a+3b=k,3a+5b=k;

我们求解ax+by=k;

当x最小时,y最大,答案就是y/a向上取整;

因为y=(k-ax)/b;

{设此时的x为x0,则满足x=x0+tb,同理满足y=y0+ta,显然t+1就是此时的答案贡献,

那么用最大的y除以a向上取整即可(注意之所以要向上取整而不是t+1,

是因为避免y=0的情况,还有注意特判x0=0的情况)}(https://www.luogu.org/space/show?uid=24553)

#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
typedef long long ll;
const int mo=1e9+7;
ll f[2000],k;
ll x,y;
int cnt;

void exgcd(ll a,ll b,ll &x,ll &y)
{
    if(!b)
    {
        x=1;y=0;
        return ;
    }
    exgcd(b,a%b,y,x);
    y-=(a/b)*x;
}

ll ans;
int main()
{
    scanf("%lld",&k);
    f[0]=1;f[1]=1;cnt=2;
    for(int i=2;i<=100;i++)
    {
        f[i]=f[i-1]+f[i-2];
        if(f[i]>k) break;
        ++cnt;
    }
    for(int i=1;i<=cnt;i++)
    {
        ll a=f[i-1],b=f[i];
        exgcd(a,b,x,y);
        x*=k;//y*=k;
        x=(x%b+b)%b;
        if(x==0) x=b;
        y=(k-a*x)/b;
        if(y<0) continue;
        ans=(ans+(y-1)/a+1)%mo;
    }
    printf("%lld",ans);
    
    return 0;
}

 

posted @ 2019-09-25 21:03  AiRomance  阅读(199)  评论(0编辑  收藏  举报