首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 其他教程 > 其他相关 >

HDU3978(又论斐波那契数列循环节)

2013-09-07 
HDU3978(再论斐波那契数列循环节)题目:http://acm.hdu.edu.cn/showproblem.php?pid3978 题意:给一个Fibna

HDU3978(再论斐波那契数列循环节)

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

 

题意:给一个Fibnacci数列,所以有f(0)=f(1)=1,然后有一个函数:G(n,i)=f(G(n,i-1)),其中有G(n,0)=f(n),然后给

三个数n,k,p,求G(n,k)%p的值。

 

分析:对于本题其实思路还算简单,就是:我们把G(n,k)写成G(n,k)=f(f(f...f(n,0)))形式,然后一层一层找循环节。

当然这个问题很早以前就做过啊,详见这里:http://blog.csdn.net/acdreamers/article/details/8226873

 

所以我们关键是先一层一层找寻环节,然后倒着计算,我认为找寻环节似乎是最不好办的,不过上次对于这个问题我已经有详

细的说明:http://blog.csdn.net/acdreamers/article/details/10983813

 

再说一遍:如果对于一个数n,找fibnacci数列模n的循环节长度,就是先对n素因子分解,然后分别计算,最后按照最小公倍

数合并,所以主要是求fibnacci模素数p的循环节长度了。这个,上次我说了有一个优美的定理。

 

定理:对于大于5的素数p,如果5是模p的二次剩余,那么fibnacci模p的循环节长度是p-1的因子,否则,如果5是模p的二次

非剩余,那么fibnacci数列模p的循环节长度是2*(p+1)的因子。

 

关于这个定理的证明就直接用费马小定理,fibnacci数列的公式,二次剩余和二次域证明即可。

 

那么,对于小于5的素数我们特殊处理即可,loop(2)=3,loop(3)=8,loop(5)=20

 

#include <iostream>#include <string.h>#include <algorithm>#include <stdio.h>#include <math.h>using namespace std;typedef long long LL;const int M=2;struct Matrix{    LL m[M][M];};Matrix per= {1,0,0,1};Matrix multi(Matrix a,Matrix b,LL MOD){    Matrix c;    int i,j,k;    for(i=0; i<M; i++)    {        for(j=0; j<M; j++)        {            c.m[i][j]=0;            for(k=0; k<M; k++)            {                c.m[i][j]+=a.m[i][k]*b.m[k][j]%MOD;            }            c.m[i][j]%=MOD;        }    }    return c;}Matrix power(Matrix a,LL k,LL MOD){    Matrix ans=per,p=a;    while(k)    {        if(k&1)        {            ans=multi(ans,p,MOD);            k--;        }        k>>=1;        p=multi(p,p,MOD);    }    return ans;}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 legendre(int a,int p){    if(quick_mod(a,(p-1)>>1,p)==1) return 1;    else                           return -1;}const int N=1000005;const int NN=50005;bool prime[N];int p[N];int num[NN],pri[NN];int num1[NN],pri1[NN];int arr[NN];int loop[N];int k,cnt,c;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 find(int n,int pri[],int num[]){    cnt=0;    int t=(int)sqrt(1.0*n);    for(int i=0; p[i]<=t; i++)    {        if(n%p[i]==0)        {            int a=0;            pri[cnt]=p[i];            while(n%p[i]==0)            {                a++;                n/=p[i];            }            num[cnt]=a;            cnt++;        }    }    if(n>1)    {        pri[cnt]=n;        num[cnt]=1;        cnt++;    }}void dfs(int dept,int product=1){    if(dept==cnt)    {        arr[c++]=product;        return;    }    for(int i=0; i<=num1[dept]; i++)    {        dfs(dept+1,product);        product*=pri1[dept];    }}int find_loop(int n){    find(n,pri,num);    int cnt1=cnt;    LL ans=1;    for(int i=0; i<cnt1; i++)    {        c=0;        int record=1;        if(pri[i]==2)            record=3;        else if(pri[i]==3)            record=8;        else if(pri[i]==5)            record=20;        else        {            if(legendre(5,pri[i])==1)                find(pri[i]-1,pri1,num1);            else                find(2*(pri[i]+1),pri1,num1);            dfs(0,1);            sort(arr,arr+c);            for(int k=0; k<c; k++)            {                Matrix A;                A.m[0][0]=1;                A.m[0][1]=1;                A.m[1][0]=1;                A.m[1][1]=0;                Matrix a=power(A,arr[k]-1,pri[i]);                int x=(a.m[0][0]+a.m[0][1])%pri[i];                int y=(a.m[1][0]+a.m[1][1])%pri[i];                if(x==1&&y==0)                {                    record=arr[k];                    break;                }            }        }        for(int k=1; k<num[i]; k++)            record*=pri[i];        ans=ans/gcd(ans,record)*record;    }    return ans;}void Solve(int p,int k){    loop[0]=p;    for(int i=1; i<=k; i++)        loop[i]=find_loop(loop[i-1]);}int work(int n,int k,int p){    int t=n;    LL ret,MOD;    Matrix ans;    Matrix A;    A.m[0][0]=1;    A.m[0][1]=1;    A.m[1][0]=1;    A.m[1][1]=0;    Solve(p,k);    for(int i=k; i>=0; i--)    {        MOD=loop[i];        ans=power(A,t,MOD);        ret=(ans.m[1][0]+ans.m[1][1])%MOD;        t=ret;    }    return ret;}int main(){    isprime();    int T,n,k,p,tt=1;    scanf("%d",&T);    while(T--)    {        scanf("%d%d%d",&n,&k,&p);        printf("Case #%d: %d\n",tt++,work(n,k,p));    }    return 0;}


 

热点排行