2016弱校联盟十一专场10.5 F. Fibonacci of Fibonacci

来源:互联网 发布:松下fp系列编程手册 编辑:程序博客网 时间:2024/04/29 20:25

2016弱校联盟十一专场10.5 F. Fibonacci of Fibonacci 题目链接:https://acm.bnu.edu.cn/v3/problem_show.php?pid=52322

题面描述:



题面描述:


Find FFn mod 20160519.


题目分析:


由于斐波那契数对M求模运算一定会产生循环节,而这个第一层循环节很容易找到,在找到循环节之后,利用矩阵连乘,快速幂求解。

或者把两层的循环节都找到,直接打印好表求解。


代码实现:

方法一:

#include <iostream>#include <cstdio>using namespace std;const long long M=20160519;const long long M1=26880696;const long long N=2;const int maxn=30000000;long long f[maxn];void qiuxunhuanjie(long long mod){    f[0]=0;    f[1]=1;    for(int i=2;i<maxn;i++)    {        f[i]=(f[i-1]%mod+f[i-2]%mod)%mod;    }    for(int i=mod-100;i<maxn;i++)    {        if(f[i]==1 && f[i+1]==1 && f[i+2]==2)        {            cout<<i<<endl;            break;        }    }///i=26880697;}struct mat{    long long m[N][N];};mat A={    1,1,    1,0};mat I={    1,0,    0,1};mat multi(mat a,mat b,long long mod){    mat c;    for(int i=0; i<N; i++)    {        for(int j=0; j<N; j++)        {            c.m[i][j]=0;            for(int k=0; k<N; k++)                c.m[i][j]+=((a.m[i][k]%mod)*(b.m[k][j]%mod))%mod;            c.m[i][j]%=mod;        }    }    return c;}mat power(mat A,long long k,long long mod)//矩阵快速幂{    mat ans=I,p=A;    while(k)    {        if(k&1)///若k为奇数,        {            ans=multi(ans,p,mod);            k--;        }        k>>=1;///k=k/2;        p=multi(p,p,mod);    }    return ans;}int main(){    ///qiuxunhuanjie(M);    int T;    long long n;    scanf("%d",&T);    while(T--)    {        scanf("%lld",&n);        mat ans=power(A,n-1,M1);        int tmp=ans.m[0][0];        //cout<<"tmp= "<<tmp<<endl;        mat ans2;        ans2=power(A,tmp-1,M);        printf("%lld\n",ans2.m[0][0]);    }    return 0;}


方法二:

利用求解循环节的方法,将循环节求解出来,然后直接应用:


求循环节代码:

#include <iostream>#include <string.h>#include <algorithm>#include <stdio.h>#include <math.h>#include <map>using namespace std;typedef long long LL;const int M = 2;struct Matrix{    LL m[M][M];};Matrix A;Matrix I = {1,0,0,1};Matrix multi(Matrix a,Matrix b,LL MOD){    Matrix c;    for(int i=0; i<M; i++)    {        for(int j=0; j<M; j++)        {            c.m[i][j] = 0;            for(int k=0; k<M; k++)                c.m[i][j] += a.m[i][k] * b.m[k][j];            c.m[i][j] %= MOD;        }    }    return c;}Matrix power(Matrix a,LL k,LL MOD){    Matrix ans = I,p = a;    while(k)    {        if(k & 1)        {            ans = multi(ans,p,MOD);            k--;        }        k >>= 1;        p = multi(p,p,MOD);    }    return ans;}int gcd(int a,int b){    return b? gcd(b,a%b):a;}const int N = 400005;const int NN = 5005;int num[NN],pri[NN];int fac[NN];bool flag[NN];int c;bool prime[N];int p[N];int k;int cnt1;int pri1[NN],num1[NN];void isprime(){    k = 0;    memset(prime,true,sizeof(prime));    for(int i=2; i<N; i++)    {        if(prime[i])        {            p[k++] = i;            for(int j=i+i; j<N; j+=i)                prime[j] = false;        }    }}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;}void Solve(int n,int pri[],int num[],int &cnt){    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 cnt,LL product,int pri1[],int num1[]){    if(dept == cnt)    {        fac[c++] = product;        return;    }    for(int i=0; i<=num1[dept]; i++)    {        dfs(dept+1,cnt,product,pri1,num1);        product *= pri1[dept];    }}map<int,int> mp;LL find_loop(LL n){    int cnt = 0;    Solve(n,pri,num,cnt);    LL ans = 1;    for(int i=0; i<cnt; i++)    {        int record=1;        if(mp.find(pri[i]) != mp.end())        {            record = mp[pri[i]];            goto Test;        }        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)            {                c = 0;                Solve(pri[i]-1,pri1,num1,cnt1);                dfs(0,cnt1,1,pri1,num1);            }            else            {                c = 0;                Solve(2*(pri[i]+1),pri1,num1,cnt1);                dfs(0,cnt1,1,pri1,num1);            }            sort(fac,fac+c);            for(int r=0; r<c; r++)                flag[r] = 1;            for(int k=c-1; k >= 0; k--)            {                if(!flag[k]) continue;                Matrix a = power(A,fac[k]-1,pri[i]);                int x = (a.m[0][0]%pri[i]+a.m[0][1]%pri[i])%pri[i];                int y = (a.m[1][0]%pri[i]+a.m[1][1]%pri[i])%pri[i];                if(x==1 && y==0)                {                    record = fac[k];                }                else                {                    for(int j=0; j<=k; j++)                    {                        if(fac[k] % fac[j] == 0)                            flag[j] = 0;                    }                }            }            mp[pri[i]] = record;        }Test:        for(int k=1; k<num[i]; k++)            record *= pri[i];        ans=ans/gcd(ans,record)*record;    }    return ans;}void Init(){    A.m[0][0] = 1;    A.m[0][1] = 1;    A.m[1][0] = 1;    A.m[1][1] = 0;}int main()///求解循环节的函数,可以求得当斐波那契数对mod=20160519取模时,循环节为:26880696 ;当对mod=26880696取模时,循环节为:746688{    //freopen("/Users/jamesqi/Desktop/in.txt","r",stdin);    int T,n;    Init();    mp.clear();    isprime();    scanf("%d",&T);    while(T--)    {        scanf("%d",&n);        LL ans = find_loop(n);        printf("%lld\n",ans);    }    return 0;}

解题代码:

#include <iostream>#include <cstdio>using namespace std;const long long M=20160519;const long long M1=26880696;const long long M2=746688;long long f[M1],f2[M2];void print(){    f[0]=0;    f[1]=1;    f2[0]=0;    f2[1]=1;    for(int i=2;i<M1;i++)    {        f[i]=(f[i-1]%M+f[i-2]%M)%M;    }    for(int i=2;i<M2;i++)    {        f2[i]=(f2[i-1]%M1+f2[i-2]%M1)%M1;    }}int main(){    int T;    long long n;    scanf("%d",&T);    print();    while(T--)    {        scanf("%lld",&n);        printf("%lld\n",f[f2[n%M2]]%M1);    }    return 0;}




0 0