Codeforces 193E Fibonacci Number

试题来源
  CODEFORCES 193E
问题描述
  Fibonacci数列模10^13下是这样定义的:
  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]);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值