HDU --- 4549 M斐波那契數列 【費馬小定理+矩陣快速冪】
阿新 • • 發佈:2019-02-07
傳送門
思路: 通過把前面幾項手推出來可以發現, 其次方項符合斐波那契數列, 又因為資料非常大, 所以就可以想到用矩陣快速冪去求得次方項, 需要注意的就是我們求的是次方, 而答案是取的某個數的該次方, 而a^b % p != a^(b%p) % p, 所以就需要加費馬小定理去 % 注意使用費馬小定理的條件p 要為質數! 所以就是 a^(p-1) % p = 1, 所以我們就可以讓b% (p - 1 ).
AC Code
#include<bits/stdc++.h>
#define CLR(x) memset(x,0,sizeof(x))
#define ll long long int
#define PI acos(-1.0)
#define db double
using namespace std;
const int maxn=1e5+5;
const int mod = 1000000007;
ll A,B,n;
struct Ma{
ll a[5][5];
void cc(){
CLR(a);
}
Ma operator * (const Ma &b) const {
Ma tmp;
tmp.cc();
for(int i=0;i<2;i++){
for (int j=0;j<2;j++){
for(int k=0;k<2;k++){
tmp.a[i][j] += (a[i][k] * b.a[k][j]);
tmp.a[i][j] %= (mod-1); //1e9+7 剛好是質數, 所以由費馬小定理, 知道當次方
//項到達1e9+6時,答案為1, 所以項數應該mod 1e9+6 , 且不會影響最終結果. 否則就會影響結果.
}
}
}
return tmp;
}
}res,x;
void init()
{
res.cc();
x.cc();
for(int i=0;i<2;i++)
res.a[i][i]=1;
x.a[0][0] = x.a[0][1] = 1;
x.a[1][0] = 1;
x.a[1][1] = 0;
}
void qpow(int t)
{
while(t){
if(t&1) res = res * x;
x = x*x;
t >>= 1;
}
}
ll pow(ll t,ll k) //這個是快速冪, 因為最後求數的幾次方的時候會用到.
{
ll sum = 1;
ll base = k;
while(t){
if(t&1){
sum *= base;
sum %= mod;
}
base *= base;
base %= mod;
t >>= 1;
}
return sum;
}
int main() //思路找到項數對應的Fiboccai 數列中對應的次方項, 分別求出在數列中的值.最後乘在一起就行了.
{
while(scanf("%lld%lld%lld",&A,&B,&n)!=EOF){
ll b[5];
b[0] = A;
b[1] = B;
if(n<2){
printf("%lld\n",b[n]);
continue;
}
ll k1=0,k2=0;
if(n<4)
k1=1;
else{
init();
qpow(n-3);
for(int i=0;i<2;i++){
k1 += res.a[i][0];
k1 %= (mod-1); //因為是次方數, 所以是mod 1e9+6;
}
}
if(n==2){
k2=1;
}
else{
init();
qpow(n-2);
for(int i=0;i<2;i++){
k2 += res.a[i][0];
k2 %= (mod-1);
}
}
ll ans = (pow(k1,A)%mod*pow(k2,B)%mod)%mod; //最終結果才是mod 1e9+7 ;
printf("%lld\n",ans);
}
}