1. 程式人生 > 其它 >裴波拉契數列II

裴波拉契數列II

技術標籤:矩陣乘法

Description

形如 1 1 2 3 5 8 13 21 34 55 89 144…的數列,求裴波拉契數列的第n項。

Input

1<n< 2 31 2^{31} 231

Output

一個數為裴波拉契數列的第n項mod 10000;

Sample Input

123456789

Sample Output

4514

思路:
一看 N N N的大小,暴力 O ( n ) O(n) O(n)遞推一定會炸掉,
我們考慮採用一種叫矩陣乘法的加速優化。
這裡就不介紹他的概念了戳這裡

矩陣乘法:
考慮一個1×2的矩陣[ f n − 2 , f n − 1 f_{n-2},f_{n-1}

fn2,fn1]
根據fibonacci數列遞推公式,我們希望通過乘以一個2×2的矩陣,
得到矩陣【f[n-1],f[n]】=【f[n-1],f[n-1]+f[n-2]】很容易構造出這個2×2矩陣A,即:

在這裡插入圖片描述

所以,有【f[1],f[2]】×A=【f[2],f[3]】
又因為矩陣乘法滿足結合律,故有:
【f[1],f[2]】× A n − 1 A^{n-1} An1=【f[n],f[n+1]】
這個矩陣的第一個元素即為所求。

#include <cstring>
#include <cstdio>
#include
<iostream>
#define ll long long using namespace std; const ll Mod = 1e4; struct node { ll x, y, a[40][40]; } A, B, C; ll n; node operator *(node x, node y) //矩陣乘法模板 { node ans; memset(ans.a, 0, sizeof(ans.a)); ans.x = x.x, ans.y = y.y; for(ll k = 1; k <= x.y; k++) for(ll i = 1; i <= x.
x; i++) for(ll j = 1; j <= y.y; j++) ans.a[i][j] = (ans.a[i][j] + x.a[i][k] * y.a[k][j] % Mod) % Mod; return ans; } void ksm(ll k) //計算A(矩陣)^n-1 { if(k == 1) {C = B; return ;} ksm(k >> 1); C = C * C; if(k & 1) C = C * B; } int main() { scanf("%lld", &n); if(n < 3) {printf("1\n"); return 0;} A.a[1][2] = A.a[1][1] = 1, A.x = 1; A.y = 2; //遞推矩陣 B.a[1][2]= B.a[2][1] = B.a[2][2] = 1, B.x = 2, B.y = 2; //構造單位矩陣 ksm(n - 1), C = A * C; printf("%lld", C.a[1][1] % Mod); return 0; }