【AcWing】蓝桥杯集训每日一题Day27|矩阵乘法|快速幂|205.斐波那契(C++)

斐波那契数列求解优化:矩阵乘法与快速幂的应用,
文章介绍了如何使用矩阵乘法和快速幂算法来高效计算斐波那契数列的第n项对10000取模的结果,以避免整数溢出问题。通过构建矩阵并利用快速幂技巧,将计算复杂度降低至O(logn),适用于大规模数据范围。
205.斐波那契
205. 斐波那契 - AcWing题库
难度:中等
时/空限制:1s / 64MB
总通过数:3220
总尝试数:4747
来源:

《算法竞赛进阶指南》
算法标签

数学知识矩阵乘法快速幂

题目内容

在斐波那契数列中,
F i b 0 = 0 , F i b 1 = 1 , F i b n = F i b n − 1 + F i b n − 2 Fib_{0}=0,Fib_{1}=1,Fib_{n}=Fib_{n-1}+Fib_{n-2} Fib0=0,Fib1=1,Fibn=Fibn1+Fibn2
(n>1)。
给定整数 n,求  F i b n Fib_{n} Fibn mod 10000。

输入格式

输入包含不超过 100 组测试用例。
每个测试用例占一行,包含一个整数 n。
当输入用例 n=−1 时,表示输入终止,且该用例无需处理。

输出格式

每个测试用例输出一个整数表示结果。
每个结果占一行。

数据范围

0≤n≤2×10^9

输入样例:
0
9
999999999
1000000000
-1
输出样例:
0
34
626
6875
题目解析

怕溢出,求第n项模10000的结果,这样就不需要写高i精度

不超过100组数据
对于每一个n,求斐波那契数列第n项模10000的结果

数据范围是0~20亿
不能用递推的方法来做,计算量是2000亿

如何优化
斐波那契数列有通项公式

a n = 1 ÷ 5 [ ( 1 + 5 2 ) n − ( 1 − 5 2 ) n ] a_{n}=1\div \sqrt{ 5 } [\left( \frac{1+\sqrt{ 5 }}{2} \right)^n-\left( \frac{1-\sqrt{ 5 }}{2} \right)^n ] an=1÷5 [(21+5 )n(215 )n]
但是这个式子不适合这道题,需要做高精度,而且还要把n项精确求出来,没办法求余数

用矩阵乘法快速幂的方式,容易取余数

如果可以把一道题目转换成矩阵的乘法来计算的话,就可以用快速幂来优化

先把递推的方法用一个矩阵表示出来
因为每一项都和前两项有关系,可以把 a n − 1 a_{n-1} an1 a n a_{n} an放到一个矩阵中,是一个1x2的矩阵
乘以一个2x2的矩阵,就可以得到一个新的1x2的矩阵
新的1x2的矩阵就是每一项往后递推, a n a_{n} an a n + 1 a_{n+1} an+1

如何构造矩阵,从定义来看
根据矩阵乘法规则
[ a n − 1 a n ] × [ 01 11 ] = [ a n a n + 1 ] \begin{bmatrix}{} a_{n-1} \qquad an \end{bmatrix} \times \begin{bmatrix}{} 0 1 \\ 11 \end{bmatrix}= \begin{bmatrix}{} a_{n} \qquad a_{n+1} \end{bmatrix} [an1an]×[0111]=[anan+1]
把矩阵第一个元素的下标当作矩阵的下标
A n = A n − 1 × F A_{n}=A_{n-1} \times F An=An1×F
同理
A n = A n − 2 × F × F A_{n}=A_{n-2} \times F \times F An=An2×F×F
… \dots
A n = A 0 × F ⋯ × F A_{n}=A_{0} \times F\dots \times F An=A0×F×F
矩阵乘法有结合律
A n = A 0 × F n A_{n}=A_{0} \times F^n An=A0×Fn
= [ 0 , 1 ] × [ 01 11 ] n =\begin{bmatrix}{} 0,1 \end{bmatrix} \times \begin{bmatrix}{} 0 1 \\ 11 \end{bmatrix}^n =[0,1]×[0111]n
求矩阵的n次方,可以类似用整数的快速幂来求
快速幂能用的前提是具有结合律

快速幂求法,时间复杂度是 O ( log ⁡ n ) O(\log n) O(logn)
矩阵乘法,复杂度再乘8

总共2万4的计算量,能过

如果用C++实现矩阵乘法的话,需要存1x2的数组和2x2的数组,还需要写两个函数,比较麻烦

如何只写一个函数

把1x2的矩阵扩充一下,下面加两个0,结果还是不变的

代码
#include <iostream>
#include <cstring>
#include <algorithm>

using namespace std;

const int MOD = 10000;

void mul(int a[][2], int b[][2])
{
	//先定义一下结果数组
	int c[2][2] = {0};
	for (int i = 0; i < 2; i ++)
		for (int j = 0; j < 2; j ++)
			for (int k = 0; k < 2; k ++)
				c[i][j] = (c[i][j] + a[i][k] * b[k][j]) % MOD;
	memcpy (a, c, sizeof c);
	//把c数组赋值到a上
}

int fib(int n)
{
	int a[2][2] = {0, 1, 0, 0};
	int f[2][2] = {0, 1, 1, 1};

	//快速幂
	while (n)
	{
		//如果n是奇数的话
		if (n & 1) mul(a, f);
		mul(f, f);
		n >>= 1;
	}
	return a[0][0];
}

int main()
{
	int n;
	//逗号表达式,值等于最后一个表达式的值,这两个式子的值其实就是n!=-1
	while (cin >> n, n != -1)
		cout << fib(n) << endl;

	return 0;
}
### 矩阵乘法的实现 在C++中,矩阵乘法可以通过自定义的数据结构和运算符重载来实现。首先定义一个`Matrix`结构体,其中包含一个二维数组用于存储矩阵元素,并通过运算符重载实现矩阵乘法操作。矩阵乘法的时间复杂度为 $ O(n^3) $,这是由于三重循环嵌套导致的[^3]。以下是矩阵乘法的具体实现: ```cpp struct Matrix { int m[101][101]; // 假设矩阵最大为100x100 Matrix() { memset(m, 0, sizeof(m)); // 初始化矩阵为0 } }; Matrix operator*(const Matrix &x, const Matrix &y) { Matrix ret; for (int i = 1; i <= n; i++) { // n为矩阵的大小 for (int j = 1; j <= n; j++) { for (int k = 1; k <= n; k++) { ret.m[i][j] = (ret.m[i][j] + (x.m[i][k] * y.m[k][j]) % MOD) % MOD; // MOD用于取模,防止溢出 } } } return ret; } ``` ### 矩阵快速幂算法的实现 矩阵快速幂算法是快速幂算法在矩阵上的扩展。与普通快速幂初始化`ans`为1类似,矩阵快速幂将`ans`初始化为单位矩阵,其作用等同于1,任何矩阵乘以单位矩阵都等于原矩阵[^4]。矩阵快速幂的时间复杂度主要取决于矩阵乘法的时间复杂度,即 $ O(n^3) $,但由于幂运算的对数时间复杂度,整体效率较高[^1]。以下是矩阵快速幂的具体实现: ```cpp Matrix MatrixQuickPower(const Matrix &A, int k) { Matrix res; for (int i = 1; i <= n; i++) { res.m[i][i] = 1; // 初始化res为单位矩阵 } while (k) { if (k & 1) { res = res * A; // 如果当前位为1,乘上当前的A } A = A * A; // A平方 k >>= 1; // 右移一位 } return res; } ``` ### 应用示例:斐波那契数列 矩阵快速幂的一个典型应用是求解斐波那契数列。通过构造一个转移矩阵 $ A = \begin{bmatrix} 0 & 1 \\ 1 & 1 \end{bmatrix} $,可以将斐波那契数列递推公式转化为矩阵乘法形式。初始矩阵为 $ [a_1, a_2] $,通过矩阵快速幂可以高效地计算出第 $ n $ 项[^5]。 ```cpp Matrix fibMatrix = {{0, 1}, {1, 1}}; // 构造转移矩阵 Matrix result = MatrixQuickPower(fibMatrix, n - 1); // 计算矩阵的n-1次幂 int fib_n = (result.m[1][1] * a1 + result.m[1][2] * a2) % MOD; // 计算第n项斐波那契数 ``` ### 总结 矩阵乘法矩阵快速幂是解决线性递推问题的重要工具。通过矩阵快速幂算法,可以将递推问题的时间复杂度从指数级降低到对数级,从而显著提高计算效率。在C++中,通过结构体和运算符重载可以方便地实现矩阵乘法矩阵快速幂算法。 ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值