有 志 者 事 竟 成,破 釜 沉 舟,百 二 秦 關 終 屬 楚;
苦 心 人 天 不 負,臥 薪 嘗 膽,三 千 越 甲 可 吞 吳!
博客有着知識錯誤,待改正之後,又是一篇好博客! 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矩陣就是中間的橋樑來記錄着每一個Fn項和Fn-1項
這裏加上一個關係式
我們很容易可以理解出A的shape一定是(2,2)那麼,怎麼怎麼去推導A呢
首先看Fn,他可以由Fn-1和Fn-2組合而成,所以第一次推到後矩陣的到
然後發現Fn-1直接和Fn-1對應
那麼結果是
然後這個A運算多少次就對應了Fn項
注意這裏填的數不是True or False,是對應的初始值
如果開頭是規定F0=0下1 2 3 5 8這樣的數列,那麼我們應該填的是
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-輪月