试题来源
CODEFORCES 193E
问题描述
Fibonacci数列模10^13下是这样定义的:
1、F0 = 0, F1 = 1
2、Fi = (Fi-1 + Fi-2) mod (10^13) (当i > 1)
John想知道x是否在这个数列当中出现过,如果出现过,最早出现在哪个位置。
1、F0 = 0, F1 = 1
2、Fi = (Fi-1 + Fi-2) mod (10^13) (当i > 1)
John想知道x是否在这个数列当中出现过,如果出现过,最早出现在哪个位置。
输入格式
输入包括一行:一个整数x,表示John想询问的数字,0<=x<10^13
输出格式
输出包括一行:如果x在上述数列中出现过,则输出其最早出现的位置,如果没有出现过,则输出-1
样例输入
13
样例输出
7
斐波那契数列是无限的,如何求?
发现递推数列会在模意义下产生循环,
可是10^13的循环节太大。
发现 10^(i+1)的循环节=10*(10^(i)的循环节) ( 3<=i )
考虑mod 10^i 下 若有 第a个数 不符合条件
那么mod 10^(i+1) 下 a,a+(10^(i)的循环节),a+2*(10^(i)的循环节),都不符合
那么我们只需要找mod 10^i 下符合的。
再在mod 10^(i+1)下验证(矩阵快速幂)
符合的不会很多,故能过。
ACcode:
#include<cstdio>
#include<cstring>
#include<cctype>
#include<algorithm>
#define LL long long
using namespace std;
LL num,mod,ans[100005],nxt[100005];
int cnt,cntn;
LL mul(LL a,LL b)
{
LL ret=0;
for(;b;b>>=1,a=(a*2)%mod) if(b&1) ret=(ret+a)%mod;
return ret;
}
struct Mat
{
LL a[2][2];
int n,m;
void Clear(int N,int M)
{
n=N,m=M;
memset(a,0,sizeof a);
}
void Unit(int sz)
{
Clear(sz,sz);
for(int i=0;i<sz;i++)
a[i][i]=1;
}
Mat operator *(const Mat &B)const
{
Mat ret;
ret.Clear(n,B.m);
for(int i=0;i<n;i++)
for(int j=0;j<B.m;j++)
for(int k=0;k<m;k++)
ret.a[i][j]=(ret.a[i][j]+mul(a[i][k],B.a[k][j]))%mod;
return ret;
}
}A;
Mat pow(Mat base,LL k)
{
Mat ret;
ret.Unit(base.n);
for(;k;k>>=1,base=base*base) if(k&1) ret=ret*base;
return ret;
}
LL F(LL id)
{
if(id==1) return 1;
if(id==0) return 0;
Mat B=pow(A,id-2);
return (B.a[0][0]+B.a[0][1])%mod;
}
int main()
{
scanf("%I64d",&num);num%=10000000000000ll;
int a=0,b=1,c;
LL *x=ans,*y=nxt,*t;
if(a==num) y[cntn++]=0;
if(b==num) y[cntn++]=1;
for(int i=2;i<=1500;i++)
{
c=(a+b)%1000;
a=b,b=c;
if(c==num%1000) y[cntn++]=i;
}
t=x,x=y,y=t,cnt=cntn,cntn=0;
A.Clear(2,2);
A.a[0][0]=A.a[1][0]=A.a[0][1]=1;
LL pret=1500;
mod=10000;
for(;mod<=10000000000000ll;mod*=10,pret*=10)
{
for(int i=0;i<=9;i++)
for(int j=0;j<cnt;j++)
if(F(i*pret+x[j])==num%mod)
y[cntn++]=i*pret+x[j];
t=x,x=y,y=t,cnt=cntn,cntn=0;
}
sort(x,x+cnt);
if(!cnt) x[0]=-1;
printf("%I64d",x[0]);
}