矩阵快素幂 板子-CSDN博客

81 阅读1分钟

求递推公式的第n项,当n很大时,用矩阵快速幂很有效。时间复杂度O(m^3*logn),m为递推公式跨越了几项。

以杭电2017女生专场赛 happy necklace 为例,看如何套板子。

\

分析的递推公式 如图:

\

根据递推公式写出计算an的矩阵,然后套下面板子(计算矩阵乘时,有优化)

#define _CRT_SECURE_NO_WARNINGS
#include <cstdio>
#include <cstring>
#include <cmath>
#include <iostream>
using namespace std;
#define MOD 1000000007
const int m = 3;//m阶矩阵
struct Matrix { //矩阵
	long long a[m][m];
	Matrix() {
		memset(a, 0, sizeof a);
	}
	Matrix operator * (const Matrix &tmp) { //重载运算符时什么时候加const?
		Matrix res = Matrix();
		for (int i = 0; i < m; ++i)
			for (int k = 0; k < m; ++k)
				if (a[i][k] != 0) {
					//这种算法,即使想算res.a[0][0]也要把三重循环进行完,
					//不同于线性代数老师教的,优点当a[][]=0时,减少计算次数
					for (int j = 0; j < m; ++j)	{ 
						res.a[i][j] += a[i][k] * tmp.a[k][j];
						if (res.a[i][j] >= MOD) res.a[i][j] %= MOD;
					}
				}			
		return res;
	}
	void operator = (const Matrix &tmp) {
		memcpy(a, tmp.a, sizeof tmp.a);
	}
	Matrix operator ^ (long long n) {
		Matrix tmp = *(this);
		Matrix ans = Matrix();
		for (int i = 0; i < m; ++i)
			ans.a[i][i] = 1;
		while (n) {
			if (n & 1) ans = ans * tmp;//若n二进制最低位为1,则乘上x^(x^i) 
			tmp = tmp * tmp; //模乘
			n >>= 1;
		}
		return ans;
	}
};

int main()
{
	int t;
	long long n;
	Matrix T = Matrix();
	Matrix A = Matrix();
	A.a[0][0] = A.a[0][2] = A.a[1][0] = A.a[2][1] = 1;
	scanf("%d", &t);
	while (t--) {
		scanf("%lld", &n);
		T = A;
		if (n == 2) puts("3");
		else if (n == 3) puts("4");
		else {
			T = T ^ (n - 3);
			long long ans = (4 * T.a[0][0]+ 3 * T.a[0][1] + 2 * T.a[0][2]) % MOD;
			printf("%lld\n", ans);
		}
	}
}

\

其中的快速幂分析,见下图

\

\

\

这不仅仅适用于求第n项,头脑风暴一下,其实其前n项和也是一个道理。

Sn = Sn-1 + f(n)._______f(n)是个递归公式。

希望以后的我,看到这能想起如何使用矩阵快速幂。

\

\