矩陣快速冪-Fibonacci

有 志 者 事 竟 成,破 釜 沉 舟,百 二 秦 關 終 屬 楚;
苦 心 人 天 不 負,臥 薪 嘗 膽,三 千 越 甲 可 吞 吳!

博客有着知識錯誤,待改正之後,又是一篇好博客! 2020.6.30🤞

矩陣快速冪-Fibonacci

LDU暑假第一次學習記

今天學習了一波矩陣快速冪,受益良多!!!
矩陣快速冪的目的就斐波那契這個例子來說,是把一個遞推式,換成可以類似於一個數一樣,來進行快速冪運算。已達到在log(n)的複雜度內實現求第n項。
首先亮出我的矩陣快速冪模板

struct Mat {
	ll m[10][10];
};
Mat Mat_mul(Mat x, Mat y, ll mat_size, ll mod) {
	Mat temp;
	memset(temp.m, 0, sizeof(temp));
	for (int i = 0; i < mat_size; i++)for (int j = 0; j < mat_size; j++)for (int k = 0; k < mat_size; k++)
		temp.m[i][j] = (temp.m[i][j] % mod + x.m[i][k] * y.m[k][j]) % mod;
	return temp;
}
Mat Create_identity_matrix(ll mat_size) {
	Mat temp;
	memset(temp.m, 0, sizeof(temp.m));
	for (int i = 0; i < mat_size; i++)temp.m[i][i] = 1;
	return temp;
}
Mat mat_qpow(Mat* mat, ll power, ll mat_size, ll mod) {
	Mat res = Create_identity_matrix(mat_size);
	while (power) {
		if (power & 1) res = Mat_mul(res, *mat, mat_size, mod);
		*mat = Mat_mul(*mat, *mat, mat_size, mod), power >>= 1;
	}
	return res;
}

用法也很簡單

int main()
{
	Mat temp;
	memset(temp.m, 0, sizeof(temp.m));
	temp.m[0][0] = temp.m[0][1] = temp.m[1][0] = 1;
	cout << mat_qpow(&temp, read, 2, 10000).m[1][0] << endl;
}

知道怎麼用了之後,咱們就開始解決如何使用應用矩陣快速冪。

應用

通常咱們用得到的幾個關係式是Fn,Sn,Pn,分別是,第n項,前n項和,前n項和的前n項和。😄
咱們用結果推前面的方法來求解A
我們可以先列出一個關係
A×(Fn1Fn2)=(FnFn1) A \times \binom{F_{n-1}}{F_{n-2}}=\binom{F_{n}}{F_{n-1}}
這個A矩陣就是中間的橋樑來記錄着每一個Fn項和Fn-1項
這裏加上一個關係式
Fn=Fn1+Fn2F_{n}=F_{n-1}+F_{n-2}
我們很容易可以理解出A的shape一定是(2,2)那麼,怎麼怎麼去推導A呢
首先看Fn,他可以由Fn-1和Fn-2組合而成,所以第一次推到後矩陣的到
(11??) \begin{pmatrix} 1 & 1 \\ ? & ? \end{pmatrix}
然後發現Fn-1直接和Fn-1對應
那麼結果是
A=(1110) A=\begin{pmatrix} 1 & 1 \\ 1 & 0 \end{pmatrix}
然後這個A運算多少次就對應了Fn
注意這裏填的數不是True or False,是對應的初始值
如果開頭是規定F0=0下1 2 3 5 8這樣的數列,那麼我們應該填的是
A=(2110) A=\begin{pmatrix} 2 & 1 \\ 1 & 0 \end{pmatrix}

Fibonacci

題目描述

我們知道斐波那契數列, F0=0, F1=1, Fn=Fn−1+Fn−2,求Fn mod 10000 。

輸入

多組數據,每組數據一行,一個整數 n。
輸入以 -1 結束。

輸出

對於每組數據,輸出 Fn mod 10000。

Sample Input

0
9
999999999
1000000000
-1

Sample Output

0
34
626
6875

Hint

n ≤ 109

題目分析
矩陣快速冪的基本應用

AC時間到

#include <unordered_map>
#include<algorithm>
#include<iostream>
#include<string.h>
#include <iomanip>
#include<stdio.h>
#include<utility>
#include<vector>
#include<string>
#include<math.h>
#include<cmath>
#include<queue>
#include<stack>
#include<deque>
#include<map>
#include<set>
#pragma warning(disable:4244)
#define PI 3.141592653589793
#pragma GCC optimize(2)
#define accelerate cin.tie(NULL);cout.tie(NULL);ios::sync_with_stdio(false);
#define EPS 1.0e-8
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const ll ll_inf = 9223372036854775807;
const int int_inf = 2147483647;
const short short_inf = 32767;
const char char_inf = 127;
ll gcd(ll a, ll b) { return b ? gcd(b, a % b) : a; }
inline ll read() {
	ll c = getchar(), Nig = 1, x = 0;
	while (!isdigit(c) && c != '-')c = getchar();
	if (c == '-')Nig = -1, c = getchar();
	while (isdigit(c))x = ((x << 1) + (x << 3)) + (c ^ '0'), c = getchar();
	return Nig * x;
}
inline void out(ll a) {
	if (a < 0)putchar('-'), a = -a;
	if (a >= 10)out(a / 10);
	putchar(a % 10 + '0');
}
ll phi(ll n)
{
	ll ans = n, mark = n;
	for (ll i = 2; i * i <= mark; i++)
		if (n % i == 0) { ans = ans * (i - 1) / i; while (n % i == 0)n /= i; }
	if (n > 1)ans = ans * (n - 1) / n; return ans;
}
ll qpow(ll x, ll n, ll mod) {
	ll res = 1;
	while (n > 0) {
		if (n & 1)res = (res * x) % mod;
		x = (x * x) % mod;
		n >>= 1;
	}
	return res;
}
struct Mat {
	ll m[10][10];
};
Mat Mat_mul(Mat x, Mat y, ll mat_size, ll mod) {
	Mat temp;
	memset(temp.m, 0, sizeof(temp));
	for (int i = 0; i < mat_size; i++)for (int j = 0; j < mat_size; j++)for (int k = 0; k < mat_size; k++)
		temp.m[i][j] = (temp.m[i][j] % mod + x.m[i][k] * y.m[k][j]) % mod;
	return temp;
}
Mat Create_identity_matrix(ll mat_size) {
	Mat temp;
	memset(temp.m, 0, sizeof(temp.m));
	for (int i = 0; i < mat_size; i++)temp.m[i][i] = 1;
	return temp;
}
Mat mat_qpow(Mat* mat, ll power, ll mat_size, ll mod) {
	Mat res = Create_identity_matrix(mat_size);
	while (power) {
		if (power & 1) res = Mat_mul(res, *mat, mat_size, mod);
		*mat = Mat_mul(*mat, *mat, mat_size, mod), power >>= 1;
	}
	return res;
}
#define Floyd for(int k = 1; k <= n; k++)for(int i=1;i<=n;i++)for(int j=1;j<=n;j++)
#define read read()
int main()
{
	Mat temp, res;
	while (1)
	{
		ll n = read;
		if (n == -1)break;
		memset(temp.m, 0, sizeof(temp.m));
		temp.m[0][0] = temp.m[0][1] = temp.m[1][0] = 1;
		out(mat_qpow(&temp, n, 2, 10000).m[1][0]);
		puts("");
	}
}

By-輪月

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章