CodeForces 193E Fibonacci Number

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

题面

题意

给出一个数n,问是否存在一个斐波那契数mod1e13后等于n,若不存在输出-1,否则输出它是第几个。

做法

首先找一下规律,发现斐波那契数在模10,100,1000,1000……下的循环节大小分别为60,300,1500,15000,150000…….并且发现后来的循环节大小每次*10。
因此我们可以考虑先暴力求出模1e5(这个范围定为1e3,1e4也行)下与给出数同余的所有数,然后将模数不断*10(直至1e13),每次模数M乘10后,与给出数同余的数一定是由,在模M/10意义下同余的数加上k(0<=k<=9)个循环节后得到的,因此在模M时,可以暴力枚举模(M/10)时同余的数加上k(0<=k<=9)个当前循环节后的数,用矩阵快速幂检验是否在模M下同余即可。
而需要注意的是,在矩阵快速幂时,因为涉及到1e13以内的数的乘法,会爆long long,所以要像乘法快速幂那样来做。

inline ll cheng(ll u,ll v)
{
    ll res=0;
    for(; v; v>>=1)
    {
        if(v&1) res=(res+u)%M;
        u=u*2%M;
    }
    return res;
}

代码

#include<iostream>
#include<cstdio>
#include<cstring>
#define ll long long
#define MAXM (ll)1e13
#define BJ 100000
#define INF 0x3f3f3f3f3f3f3f3f
using namespace std;

ll n,m,a,b=1,c,can[BJ*10],cc,M,tmp[BJ*10],ans=INF,XH;
inline ll cheng(ll u,ll v)
{
    ll res=0;
    for(; v; v>>=1)
    {
        if(v&1) res=(res+u)%M;
        u=u*2%M;
    }
    return res;
}
struct Jz
{
    ll num[2][2];
    Jz()
    {
        memset(num,0,sizeof(num));
    }
    Jz operator * (const Jz &u) const
    {
        Jz res;
        ll i,j,k;
        for(i=0; i<2; i++)
        {
            for(j=0; j<2; j++)
            {
                for(k=0; k<2; k++)
                {
                    res.num[i][j]=(res.num[i][j]+cheng(num[i][k],u.num[k][j]))%M;
                }
            }
        }
        return res;
    }
} dw;

inline Jz po(Jz u,ll v)
{
    Jz res;
    res.num[0][0]=res.num[1][1]=1;
    for(; v;)
    {
        if(v&1) res=res*u;
        u=u*u;
        v>>=1;
    }
    return res;
}

inline ll ask(ll u)
{
    Jz res=po(dw,u);
    return res.num[0][0];
}

int main()
{
    dw.num[0][1]=dw.num[1][0]=dw.num[1][1]=1;
    ll i,j,k,t;
    cin>>n;
    t=n%BJ;
    for(i=1;; i++)
    {
        if(t==a) can[++cc]=i;
        c=(a+b)%BJ;
        a=b,b=c;
        if(!a&&b==1) break;
    }
    for(M=BJ*10,XH=150000; M<=MAXM; M*=10,XH*=10)
    {
        t=n%M,k=0;
        for(i=1; i<=cc; i++)
        {
            for(j=0; j<=9; j++)
            {
                if(ask(can[i]+XH*j)%M==t)
                {
                    tmp[++k]=can[i]+XH*j;
                }
            }
        }
        for(i=1; i<=k; i++) can[i]=tmp[i];
        cc=k;
    }
    if(!cc)
    {
        puts("-1");
        return 0;
    }
    for(i=1; i<=cc; i++) ans=min(ans,can[i]);
    cout<<ans-1;
}

猜你喜欢

转载自blog.csdn.net/yzyyylx/article/details/81474909