解题报告:HDU4549 M斐波那契数列 数论三大基础(快速幂+矩阵快速幂+费马小定理)

本文介绍了一种解决M斐波那契数列问题的方法,利用矩阵快速幂和费马小定理,有效地计算了特定条件下数列第N项的值,并通过模运算避免了数值溢出。

M斐波那契数列

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


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:   5808  5807  5806  5805  5804 
 

Statistic |  Submit |  Discuss | Note


题意:
给A,B,N求A^Fi(n)*B^Fi(n-1)%mod。
这题真的有趣,将三个基础的数论知识巧妙的结合在一起,正好一起记录一下。

思路:
首先我们要求Fi第N项和N-1项,要用到矩阵快速幂,快速幂时的值肯定会爆long long,因为Fi[N]的值要做幂,所以不能直接%mod,幂上的mod优化就是费马小定理了,mod(1e9+7)为质数,且与A,B互质,那么(A,B)^(mod-1)%mod=1;最后求出幂数再用快速幂得出答案。最后注意n为0,1特判一下。

代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>

const int mod = 1e9+7;
using namespace std;

long long a,b,c;

inline long long q_pow(long long x,long long y){
    long long res = 1;
    x %= mod;
    while(y){
        if(y&1){
            res = res * x % mod;
        }x = x * x % mod;
        y>>=1;
    }return res ;
}

inline long long work(){
    if(c==0){
        return a;
    }if(c==1){
        return b;
    }c--;
    long long t[2][2]={1,1,1,0};
    long long res[2][2]={1,0,0,1};
    long long tmp[2][2];
    while(c){
        if(c&1){
            for(int i=0;i<2;i++){
                for(int j=0;j<2;j++){
                    tmp[i][j] = res[i][j];
                }
            }memset(res,0,sizeof(res));
            for(int i=0;i<2;i++){
                for(int j=0;j<2;j++){
                    for(int k=0;k<2;k++){
                        res[i][j] = (res[i][j]+tmp[i][k]*t[k][j])%(mod-1);
                    }
                }
            }
        }

        for(int i=0;i<2;i++){
            for(int j=0;j<2;j++){
                tmp[i][j] = t[i][j];
            }
        }memset(t,0,sizeof(t));

        for(int i=0;i<2;i++){
            for(int j=0;j<2;j++){
                for(int k=0;k<2;k++){
                    t[i][j] = ( t[i][j] + tmp[i][k] * tmp[k][j] )%(mod-1);
                }
            }
        }c>>=1;
    }
    return q_pow(b,res[0][0])*q_pow(a,res[0][1])%mod;
}

int main()
{
    while(cin>>a>>b>>c){
        cout<<work()<<endl;
    }return 0;
}




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值