HDOJ M斐波那契数列 4549【矩阵快速幂+快速幂+费马小定理+欧拉函数】



M斐波那契数列

Time Limit: 3000/1000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others)
Total Submission(s): 2096    Accepted Submission(s): 596


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

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

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

Input
输入包含多组测试数据;
每组数据占一行,包含3个整数a, b, n( 0 <= a, b, n <= 10^9 )
 

Output
对每组测试数据请输出一个整数F[n],由于F[n]可能很大,你只需输出F[n]对1000000007取模后的值即可,每组数据输出一行。
 

Sample Input
      
      
0 1 0 6 10 2
 

Sample Output
      
      
0 60
 

Source
 

Recommend
liuyiding   |   We have carefully selected several similar problems for you:   5390  5389  5388  5387  5386 
 


题目分析:

此题是求的相乘的斐波那契数,开始看成求相加斐波那契,以为是很裸的矩阵快速幂。。。

不过,此题虽然让求的是相乘的过程。但是当你写出几个数之后就会发现这些数的指数是成斐波那契数列的。

3  4  12  48.....  ==>  3^1*4^0   3^0*4^1   3^1*4^1    3^1*4^2.........

我们可以求出让求的第n项指数是多少。但是因为让求的数比较多,所以结果肯定会比较大,我们要想到对指数取余。我们想到费马小定理:

a ^ n = a ^ (n % euler ( M ) )*( mod M )

题目中说的是结果对M=1000000007取余,所以我们对指数取余的数应为euler(M)。因为M是素数,所以euler(M)=1000000006。

下面我们很容易就能找到相乘的矩阵,进行快速幂。不过注意题目的n,题目n代表的是n+1项。

开始的时候我找的相乘的矩阵是3*3的矩阵。。。。开始TLE了,以为是矩阵的原因,改成了2*2的。。。逗比了。。其实不是矩阵太大。。多了一维而已慢不了哪里。。主要是应该long long型的,写int就TLE。。。long long就过了。

AC代码。。3*3的相乘矩阵

#include <stdio.h>
#include <math.h>
#include <vector>
#include <queue>
#include <string>
#include <string.h>
#include <stdlib.h>
#include <iostream>
#include <algorithm>

using namespace std;

const int Modn = 1000000007;
const int MAXN = 3;
typedef long long LL;
LL res[MAXN][MAXN];

void Matmul(LL X[MAXN][MAXN],LL Y[MAXN][MAXN])
{
    int t[MAXN][MAXN]={0};
    for(int i=0;i<MAXN;i++){
        for(int k=0;k<MAXN;k++){
            if(X[i][k])
                for(int j=0;j<MAXN;j++)
                t[i][j]=(t[i][j]+X[i][k]*Y[k][j]%(Modn-1))%(Modn-1);
        }
    }
    for(int i=0;i<MAXN;i++)
        for(int j=0;j<MAXN;j++)
        X[i][j]=t[i][j];
}

void Matrix(LL X[MAXN][MAXN],LL n)
{
    for(int i=0;i<MAXN;i++){
        //res[i][i]=1;
        for(int j=0;j<MAXN;j++)
            res[i][j]=(i==j);
    }
    while(n){
        if(n&1) Matmul(res,X);
        Matmul(X,X);
        n>>=1;
    }
}

LL power(LL x,LL n)
{
    x%=Modn;
    LL res=1;
    while(n){
        if(n&1) res=res*x%Modn;
        x=x*x%Modn;
        n>>=1;
    }
    return res;
}

int main()
{

    LL a,b,n;
    while(scanf("%lld%lld%lld",&a,&b,&n)!=EOF){
        if(n<3){
            if(n==0)printf("%lld\n",a);
            else if(n==1) printf("%lld\n",b);
            else if(n==2) printf("%lld\n",a*b);
            continue;
        }
        LL num[MAXN][MAXN];
        LL f[3];
        memset(num,0,sizeof(num));
        num[0][0]=num[0][1]=1;
        num[1][2]=num[1][0]=1;
        Matrix(num,n-2);//(n+1)-3;
        f[2]=1;f[1]=0;f[0]=1;
        LL ans1=0;
        for(int j=0;j<3;j++)
            ans1=(ans1+f[j]*res[j][0]%(Modn-1))%(Modn-1);
        f[2]=0;f[1]=1;f[0]=1;
        LL ans2=0;
        for(int j=0;j<3;j++)
            ans2=(ans2+f[j]*res[j][0]%(Modn-1))%(Modn-1);
        LL cnt=power(a,ans1)*power(b,ans2)%Modn;
        printf("%lld\n",cnt);
    }
    return 0;
}

2*2的相乘矩阵

#include <stdio.h>
#include <math.h>
#include <vector>
#include <queue>
#include <string>
#include <string.h>
#include <stdlib.h>
#include <iostream>
#include <algorithm>

using namespace std;

const int Modn = 1000000007;
const int MAXN = 2;
typedef long long LL;
LL res[MAXN][MAXN];

void Matmul(LL X[MAXN][MAXN],LL Y[MAXN][MAXN])
{
    LL t[MAXN][MAXN]={0};
    for(int i=0;i<MAXN;i++){
        for(int k=0;k<MAXN;k++){
            if(X[i][k])
                for(int j=0;j<MAXN;j++)
                t[i][j]=(t[i][j]+X[i][k]*Y[k][j]%(Modn-1))%(Modn-1);
        }
    }
    for(int i=0;i<MAXN;i++)
        for(int j=0;j<MAXN;j++)
        X[i][j]=t[i][j];
}

void Matrix(LL X[MAXN][MAXN],LL n)
{
    for(int i=0;i<MAXN;i++){
        //res[i][i]=1;
        for(int j=0;j<MAXN;j++)
            res[i][j]=(i==j);
    }
    while(n){
        if(n&1) Matmul(res,X);
        Matmul(X,X);
        n>>=1;
    }
}

LL power(LL x,LL n)
{
    x%=Modn;
    LL ans=1;
    while(n){
        if(n&1) ans=ans*x%Modn;
        x=x*x%Modn;
        n>>=1;
    }
    return ans;
}

int main()
{

    LL a,b,n;
    while(scanf("%lld%lld%lld",&a,&b,&n)!=EOF){
        if(n<3){
            if(n==0)printf("%lld\n",a);
            else if(n==1) printf("%lld\n",b);
            else if(n==2) printf("%lld\n",a*b);
            continue;
        }
        LL num[MAXN][MAXN];
        LL f[3];
        num[0][0]=num[1][0]=num[0][1]=1;
        num[1][1]=0;
        Matrix(num,n-1);//(n+1)-3;
        f[1]=1;f[0]=0;
        LL ans1=0;
        for(int j=0;j<MAXN;j++)
            ans1=(ans1+f[j]*res[j][0]%(Modn-1))%(Modn-1);
        //printf("%d ",ans1);
        f[1]=0;f[0]=1;
        LL ans2=0;
        for(int j=0;j<MAXN;j++)
            ans2=(ans2+f[j]*res[j][0]%(Modn-1))%(Modn-1);
        //printf("%d \n",ans2);
        LL cnt=power(a,ans1)*power(b,ans2)%Modn;
        printf("%lld\n",cnt);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值