2013金山西山居创意游戏程序挑战赛——初赛(2) B M斐波那契数 (hdu 4549 )


M斐波那契数列F[n]是一种整数数列,它的定义如下:

F[0] = a
F[1] = b
F[n] = F[n-1] * F[n-2] ( n > 1 )

现在给出a, b, n,你能求出F[n]的值吗?


思路:首先我们很容易得F[n]的通项公式,对F[n]=a^(f[n-1])*b^(f[n]),其中f[n]为斐波那契数列的第n项。由于我们要求的n很大(最大可达到10^9),所以我们不能直接求,时我们可以用矩阵加速用O(logn)的复杂度来求f[n],然后再用乘方快速幂求最终的结果。但是我们这里要求的结果是模上1000000007后(设为mod)的值,所以在矩阵加速的时候不能直接模上mod。这里用到了一个数论的知识,就是a,b互质,则a^(b-1)%b==1,因为mod是一个素数,所以对于任何a,b(a,b<=10^9),都与mod互质,所以我们最终即a^(f[n-1]%(mod-1))*b^(f[n]%(mod-1))%mod,这下就可以用矩阵快速幂来求解了。

代码如下:

#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <string.h>
#define maxn 3
#define mod 1000000006
using namespace std;
typedef long long LL;
LL c[100][maxn][maxn];
LL ans[maxn][maxn];
int m=2;
void init(LL a[maxn][maxn],LL b[maxn][maxn], LL c[maxn][maxn])
{
    int i,j,k;
    LL tmp[maxn][maxn];
    memset(tmp,0,sizeof(tmp));
    for(i=1;i<=m;i++)
    {
        for(j=1;j<=m;j++)
        {
            for(k=1;k<=m;k++)
            {
                tmp[i][j]+=b[i][k]*c[k][j];
                tmp[i][j]%=mod;
            }
        }
    }
    for(i=1;i<=m;i++)
    {
        for(j=1;j<=m;j++)
        a[i][j]=tmp[i][j];
    }
}
void build(int num)
{
    if(num==1)
    return;
    build(num-1);
    init(c[num],c[num-1],c[num-1]);
}
LL abmodn(LL a,LL b,LL n)
{
    LL d=1,i,bi[40],num=0;
    while(b>0)
    {
        bi[num++]=b%2;
        b/=2;
    }
    for(i=num-1;i>=0;i--)
    {
        d=(d*d)%n;
        if(bi[i])
        d=(a*d)%n;
    }
    return d;
}
void solve(int n,int a,int b)
{
    memset(ans,0,sizeof(ans));
    int t[55],num=0;
    while(n)
    {
        t[++num]=n%2;
        n/=2;
    }
    build(num);
    int i,j;
    for(i=1;i<=m;i++)
    {
        for(j=1;j<=m;j++)
        ans[i][j]=c[num][i][j];
    }
    for(i=1;i<num;i++)
    {
        if(t[i])
        {
            init(ans,ans,c[i]);
        }
    }
    LL x=(ans[1][1]+ans[2][1])%mod,y=(ans[1][2]+ans[2][2])%mod;
    LL ANS=(abmodn(a,x,mod+1)*abmodn(b,y,mod+1))%(mod+1);
    printf("%I64d\n",ANS);
}
int main()
{
   // freopen("dd.txt","r",stdin);
    c[1][1][1]=0;
    c[1][2][1]=c[1][1][2]=c[1][2][2]=1;
    int a,b,n;
    while(scanf("%d%d%d",&a,&b,&n)!=EOF)
    {
        if(n==0)
        printf("%d\n",a);
        else if(n==1)
        printf("%d\n",b);
        else if(n==2)
        printf("%I64d\n",(LL)a*b%(mod+1));
        else
        {
            solve(n-2,a,b);
        }
    }
    return 0;
}


原文地址:https://www.cnblogs.com/javawebsoa/p/3087228.html