CodeForces 193E Fibonacci Number

題面

題意

給出一個數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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章