矩阵快速幂模板-Fibonacci

42 篇文章 1 订阅
2 篇文章 0 订阅

有 志 者 事 竟 成,破 釜 沉 舟,百 二 秦 关 终 属 楚;
苦 心 人 天 不 负,卧 薪 尝 胆,三 千 越 甲 可 吞 吴!

矩阵快速幂-Fibonacci

LDU暑假第一次学习记

今天学习了一波矩阵快速幂,受益良多!!!
矩阵快速幂的目的就斐波那契这个例子来说,是把一个递推式,换成可以类似于一个数一样,来进行快速幂运算。已达到在log(n)的复杂度内实现求第n项。
首先亮出我的矩阵快速幂模板

#define mat_mod 2009
struct Mat {
	ll m[10][10];
};
Mat Mul(Mat A, Mat B, ll mat_size) {
	Mat res;
	memset(res.m, 0, sizeof(res.m));
	for (int i = 0; i < mat_size; i++)for (int j = 0; j < mat_size; j++)for (int k = 0; k < mat_size; k++)
		res.m[i][j] = (res.m[i][j] + (A.m[i][k] * B.m[k][j]) % mat_mod) % mat_mod;
	return res;
}
Mat mat_qpow(Mat data, ll power, ll mat_size) {
	Mat res;
	memset(res.m, 0, sizeof(res.m));
	for (int i = 0; i < mat_size; i++)res.m[i][i] = 1;
	while (power) {
		if (power & 1)res = Mul(res, data, mat_size);
		data = Mul(data, data, mat_size), power >>= 1;
	}
	return res;
}

用法也很简单

int main()
{
	//前提修改mod不可将mod传参,否则很慢
	Mat temp;
	memset(temp.m, 0, sizeof(temp.m));
	temp = mat_qpow(temp, 2000, 10);
}

知道怎么用了之后,咱们就开始解决如何使用应用矩阵快速幂。

应用

根据对应关系,得出一个矩阵。通过递归得到最后的ans
就拿Fibonacci数列的前n项和举例子吧。
首先咱们要有几个对应的关系式
Fn=Fn-1+Fn-2
Sn=Sn-1+Fn
然后咱们列出对应矩阵关系
( f n f n − 1 S n ) = ( _ _ _ _ _ _ _ _ _ ) × ( f n − 1 f n − 2 S n − 1 ) 通 过 求 解 得 出 矩 阵 为 ( 1 1 0 1 0 0 1 1 1 ) \begin{pmatrix} f_{n} \\ f_{n-1}\\S_{n} \end{pmatrix}=\begin{pmatrix} \_ & \_ &\_ \\ \_ & \_ &\_ \\\_ & \_ &\_ \end{pmatrix}\times \begin{pmatrix} f_{n-1} \\ f_{n-2} \\S_{n-1}\end{pmatrix} \\通过求解得出矩阵为\\\begin{pmatrix} 1& 1 &0 \\ 1 & 0 &0 \\1 & 1 &1 \end{pmatrix} fnfn1Sn=_________×fn1fn2Sn1111101001
这应该如何理解呢,其实就是对应的系数组成矩阵,因为fn=1×fn-1+1×fn-2。fn-1=1×fn-1。Sn=1×Sn-1+1×fn=1×Sn-1+1×fn-1+1×fn-2
然后通过递归化简得到了最终的结果。演示一下过程
( f n f n − 1 S n ) = ( 1 1 0 1 0 0 1 1 1 ) × ( f n − 1 f n − 2 S n − 1 ) = ( 1 1 0 1 0 0 1 1 1 ) × ( 1 1 0 1 0 0 1 1 1 ) × ( f n − 2 f n − 3 S n − 2 ) = ( 1 1 0 1 0 0 1 1 1 ) 2 × ( f n − 2 f n − 3 S n − 2 ) . . . . . = ( 1 1 0 1 0 0 1 1 1 ) n − 2 × ( f 2 f 1 S 2 ) \begin{pmatrix} f_{n} \\ f_{n-1}\\S_{n} \end{pmatrix}=\begin{pmatrix} 1& 1 &0 \\ 1 & 0 &0 \\1 & 1 &1 \end{pmatrix}\times \begin{pmatrix} f_{n-1} \\ f_{n-2} \\S_{n-1}\end{pmatrix}=\begin{pmatrix} 1& 1 &0 \\ 1 & 0 &0 \\1 & 1 &1 \end{pmatrix}\times\begin{pmatrix} 1& 1 &0 \\ 1 & 0 &0 \\1 & 1 &1 \end{pmatrix}\times \begin{pmatrix} f_{n-2} \\ f_{n-3} \\S_{n-2}\end{pmatrix}=\\\begin{pmatrix} 1& 1 &0 \\ 1 & 0 &0 \\1 & 1 &1 \end{pmatrix}^{2}\times \begin{pmatrix} f_{n-2} \\ f_{n-3} \\S_{n-2}\end{pmatrix}.....=\begin{pmatrix} 1& 1 &0 \\ 1 & 0 &0 \\1 & 1 &1 \end{pmatrix}^{n-2}\times \begin{pmatrix} f_{2} \\ f_{1} \\S_{2}\end{pmatrix} fnfn1Sn=111101001×fn1fn2Sn1=111101001×111101001×fn2fn3Sn2=1111010012×fn2fn3Sn2.....=111101001n2×f2f1S2
从而得到
( f n + 1 f n S n + 1 ) = ( 1 1 0 1 0 0 1 1 1 ) n − 1 × ( f 2 f 1 S 2 ) \begin{pmatrix} f_{n+1} \\ f_{n}\\S_{n+1} \end{pmatrix}=\begin{pmatrix} 1& 1 &0 \\ 1 & 0 &0 \\1 & 1 &1 \end{pmatrix}^{n-1}\times \begin{pmatrix} f_{2} \\ f_{1} \\S_{2}\end{pmatrix} fn+1fnSn+1=111101001n1×f2f1S2
结果一目了然,直接利用这个关系式得出对应的值。

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

题目分析
矩阵快速幂的基本应用
这里的矩阵关系为 M a t = ( 1 1 1 0 ) Mat=\begin{pmatrix} 1& 1 \\ 1 & 0 \end{pmatrix} Mat=(1110)
( f n + 1 f n ) = M a t n − 1 × ( f 2 f 1 ) \begin{pmatrix} f_{n+1} \\ f_{n} \end{pmatrix}=Mat^{n-1} \times\begin{pmatrix} f_{2} \\ f_{1} \end{pmatrix} (fn+1fn)=Matn1×(f2f1)

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;
	while (1)
	{
		ll n = read;
		if (n == -1)break;
		if (!n) { puts("0"); continue; }
		temp.m[0][0] = temp.m[0][1] = temp.m[1][0] = 1;
		temp.m[1][1] = 0;
		temp = mat_qpow(&temp, n - 1, 2, 10000);
		out((temp.m[1][0] + temp.m[1][1]) % 10000);
		puts("");
	}
}

PS:
上述的代码的矩阵快速幂有些慢,原因在于传的参数过多,修改成开头放置的就可。思路没变,只需要修改模板就可以。

By-轮月

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Round moon

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值