HDU 4549 M斐波那契数列(矩阵快速幂&费马小定理)
Posted shiyicode
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了HDU 4549 M斐波那契数列(矩阵快速幂&费马小定理)相关的知识,希望对你有一定的参考价值。
ps:今天和战友聊到矩阵快速幂,想到前几天学长推荐去刷矩阵专题,挑了其中唯一一道中文题,没想到越过山却被河挡住去路。。。
题目链接:[kuangbin带你飞]专题十九 矩阵 R - M斐波那契数列
Time Limit:1000MS Memory Limit:32768KB 64bit IO Format:%I64d & %I64u
题意
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取模后的值即可,每组数据输出一行。
思路
一看到题,就拿二维01矩阵变来变去尝试半天,无果,就手推了几部,猛然发现f[i] = a^fib[i- 1]*b^fib[i]。道友们动动手,很容易就能发现。
然后就是刷刷的矩阵快速幂求fib,求出两数,再快速幂,结果得出,俩样例试过没问题,提交,wrong。。。
找来找去,找不出错误在哪,去百度了下,发现别人在对矩阵快速幂的时候都是对MOD-1取余的,顿时纳闷,才发现自己忽略了a^b时迭代时不能直接取余的。
看解释说是由费马小定理可以得出循环节是MOD-1,所以对MOD-1取余。仔细的看了费马小定理,似懂非懂的,至于循环节,压根就没想通,可怜在数论上几近一张白纸的我。(ps:过两天好好研究研究)
代码
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <cstdlib>
#include <vector>
#include <cmath>
#include <map>
using namespace std;
#define LL long long
const int MOD = 1000000007;
struct Node
{
LL a, b, c, d;
Node(){};
Node(LL a, LL b, LL c, LL d)
:a(a),b(b),c(c),d(d){}
Node operator*(const Node& t)
{
Node ans;
ans.a = ((this->a*t.a)%(MOD-1)+(this->b*t.c)%(MOD-1))%(MOD-1);
ans.b = ((this->a*t.b)%(MOD-1)+(this->b*t.d)%(MOD-1))%(MOD-1);
ans.c = ((this->c*t.a)%(MOD-1)+(this->d*t.c)%(MOD-1))%(MOD-1);
ans.d = ((this->c*t.b)%(MOD-1)+(this->d*t.d)%(MOD-1))%(MOD-1);
return ans;
}
};
LL qpower(LL n, LL x)
{
LL ans = 1;
LL p = x;
while(n)
{
if(n & 1)
ans = (ans*p)%MOD;
p = (p*p)%MOD;
n >>= 1;
}
return ans;
}
int main()
{
LL a, b, n;
while(cin>>a>>b>>n)
{
Node p = Node(0, 1, 1, 1);
Node ans = Node(1, 0, 0, 1);
if(n == 0)
{
cout<<a<<endl;
continue;
}
--n;
while(n)
{
if(n & 1)
ans = ans*p;
p = p*p;
n >>= 1;
}
LL fiba = ans.b;
LL fibb = ans.d;
LL rel = 0;
rel = (qpower(fiba, a) * qpower(fibb, b))%MOD;
cout<<rel<<endl;
}
}
以上是关于HDU 4549 M斐波那契数列(矩阵快速幂&费马小定理)的主要内容,如果未能解决你的问题,请参考以下文章