HDU 4549 M斐波那契数列(矩阵快速幂+费马小定理)

13 篇文章 0 订阅
4 篇文章 0 订阅

M斐波那契数列

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


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
 

中文题意。

POINT://其实还没学过矩阵到底怎么算,只知道2乘2的。

学习矩阵快速幂,可以用来求斐波那契数列。毕竟n非常大,递归肯定超时。

自己理解了一下,写了一个很丑的矩阵快速幂,只能求斐波那契数列。

费马小定理2:

我们可以利用费马小定理来简化幂模运算:由于a^(p-1)≡a^0≡1(mod p),所以a^x(mod p)有循环节,长度为p-1,所以a^x≡a^(x%(p-1))(mod p)



#include <iostream>
#include <string.h>
#include <stdio.h>
#include <stack>
#include <algorithm>
#include <math.h>
using namespace std;
#define ll long long
const ll p =1e9+7;
const ll m=p-1;
    ll a,b,n;
struct node
{
    ll x11,x12,x21,x22;
};
node chen(node a,node b)
{
    node ans;
    (ans.x11=a.x11*b.x11+a.x12*b.x21)%=m;
    (ans.x12=a.x11*b.x12+a.x12*b.x22)%=m;
    (ans.x21=a.x21*b.x11+a.x22*b.x21)%=m;
    (ans.x22=a.x21*b.x12+a.x22*b.x22)%=m;
    return ans;
}
node jqkm(node now,ll mi)
{
    if(mi<=0) return now;
    node ans;
    ans.x11=1,ans.x12=0,ans.x21=0,ans.x22=1;
    while(mi)
    {
        if(mi&1)
        {
            ans=chen(ans,now);
        }
        mi=mi>>1;
        now=chen(now,now);
    }
    return ans;
}
ll qkm(ll now, ll mi)
{
    ll ans=1;
    while(mi)
    {
        if(mi&1)
            (ans*=now)%=p;
        mi=mi>>1;
        (now=now*now)%=p;
    }
    return ans;
}
ll baoli(ll x)
{
    if(x==0) return a;
    if(x==1) return b;
    return baoli(x-1)*baoli(x-2)%p;
}
int main()
{
    while(~scanf("%lld %lld %lld",&a,&b,&n))
    {
        ll f1=1,f2=2;
        ll na,nb;
        if(n<4)
        {
            printf("%lld\n",baoli(n));
        }
        else
        {
            node ans;
            node now;
            now.x11=1,now.x12=1,now.x21=1,now.x22=0;
            ans=jqkm(now,n-3);
            nb=ans.x11*f2+ans.x12*f1;
            na=ans.x21*f2+ans.x22*f1;
            printf("%lld\n",qkm(a,na)*qkm(b,nb)%p);
        }
    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值