版权声明:本文为博主原创文章,未经博主允许不得转载。 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;
}