zoukankan      html  css  js  c++  java
  • HDU3977(斐波那契数列模n的循环节长度)

    题目:http://acm.hdu.edu.cn/showproblem.php?pid=3977

    题意:求斐波那契数列模p的循环节长度,注意p最大是2*10^9,但是它的素因子小于10^6。

    分析过程:首先我们知道fib数列模p如果出现了连续的1,0就意味这着开始循环了,因为接下来的项就是1 1 2 3 5等等。

    那么很显然如果在第k位第一次出现了1,0,那么对于以后的1,0都可以表示为k*m。

    那么,现在我们考虑如果fib数列模p在第pos位第一次出现了0,那么设0前面的那个数为a,则接下来的序列将是a,0,a,

    a,2a,3a,5a,8a,....。可以看出a的系数就是一个fib数列,那么我们就可以得到fib(k+i)%p=a*fib(i)%p,其中i满

    0<i<k,所以进一步可以得到fib(i)=[a^j*fib(i-k*j)]%p。

    那么我们现在先来说说如何求fib数模一个正整数n的循环节长度:

    对于这个问题,我们先对n进行素因子分解,得到:,然后先对每一个形如p^k的数计算循环节,然后它们

    的最小公倍数就是n的循环节长度(当然这里面涉及到CRT等等方面的基础)。那么现在问题就是计算p^k的循环节,这个问题

    可以进一步简化成求G(p)*p^(k-1)。其中G(p)表示fib数列模素数p的循环节长度,所以现在的问题是如何求fib数列模一个

    小于10^6的素数p的循环节长度。

    求fib数列模p(p是素数)的最小循环节方法:

    暴力枚举fib[i]%p==0的最小的i,然后记录pos=i+1,设a为fib[i]%p==0的前一位数,即a=fib[i-1]

    那么我们知道fib数列模p的最小循环节长度一定是pos*x,那么也就是说现在要求一个最小的数x,满足,

    求出x后,那么问题就解决了,剩下的就是合并等等。

    #include <iostream>
    #include <string.h>
    #include <algorithm>
    #include <stdio.h>
    #include <math.h>
    
    using namespace std;
    typedef long long LL;
    const int N=1000005;
    
    bool prime[N];
    int p[N];
    int pri[N];
    int num[N];
    int f[N];
    int fac[N];
    int arr[N];
    int k,cnt;
    
    void isprime()
    {
        k=0;
        int i,j;
        memset(prime,true,sizeof(prime));
        for(i=2; i<N; i++)
        {
            if(prime[i])
            {
                p[k++]=i;
                for(j=i+i; j<N; j+=i)
                {
                    prime[j]=false;
                }
            }
        }
    }
    
    void Solve(LL n)
    {
        cnt=0;
        int ct=0;
        int t=(int)sqrt(n*1.0);
        for(int i=0; p[i]<=t; i++)
        {
            if(n%p[i]==0)
            {
                ct=0;
                pri[cnt]=p[i];
                while(n%p[i]==0)
                {
                    ct++;
                    n/=p[i];
                }
                num[cnt]=ct;
                cnt++;
            }
        }
        if(n>1)
        {
            pri[cnt]=n;
            num[cnt]=1;
            cnt++;
        }
    }
    
    LL gcd(LL a,LL b)
    {
        return b? gcd(b,a%b):a;
    }
    
    LL quick_mod(LL a,LL b,LL m)
    {
        LL ans=1;
        a%=m;
        while(b)
        {
            if(b&1)
            {
                ans=ans*a%m;
                b--;
            }
            b>>=1;
            a=a*a%m;
        }
        return ans;
    }
    
    int main()
    {
        isprime();
        int T,a,pos,tt=1;
        LL n;
        cin>>T;
        while(T--)
        {
            cin>>n;
            printf("Case #%d: ",tt++);
            Solve(n);
            pos=0;
            for(int k=0; k<cnt; k++)
            {
                f[0]=f[1]=1;
                for(int i=2;; i++)
                {
                    f[i]=(f[i-1]+f[i-2])%pri[k];
                    if(f[i]==0)
                    {
                        a=f[i-1];
                        pos=i+1;
                        break;
                    }
                }
                int cv=0;
                int tmp=pri[k]-1;
                int t=(int)sqrt(tmp*1.0);
                for(int i=1; i<=t; i++)
                {
                    if(tmp%i==0)
                    {
                        if(tmp/i==i)
                            fac[cv++]=i;
                        else
                        {
                            fac[cv++]=i;
                            fac[cv++]=tmp/i;
                        }
                    }
                }
                int record=0;
                sort(fac,fac+cv);
                for(int i=0; i<cv; i++)
                {
                    if(quick_mod(a,fac[i],pri[k])==1)
                    {
                        record=fac[i];
                        break;
                    }
                }
                LL ans=record*pos;
                for(int i=1; i<num[k]; i++)
                    ans*=pri[k];
                arr[k]=ans;
            }
            LL ret=1;
            for(int i=0; i<cnt; i++)
                ret=ret/gcd(ret,arr[i])*arr[i];
            cout<<ret<<endl;
        }
        return 0;
    }


     

  • 相关阅读:
    mySQL练习题
    JAVA实现C/S结构小程序
    JavaLinkedHashSet练习
    关于Extjs删除分页后删除最后一条数据页面无效的问题。
    hibernate 插入,更新数据库错误
    错误!错误!错误!
    坑爹的oracle
    关于hibernate实体类
    第一个项目的需求分析
    Ueditor 单独使用上传图片及上传附件方法
  • 原文地址:https://www.cnblogs.com/riskyer/p/3299306.html
Copyright © 2011-2022 走看看