矩阵快素幂 板子

来源:互联网 发布:卖家开通淘宝客要求 编辑:程序博客网 时间:2024/06/18 07:23

求递推公式的第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 1000000007const 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)是个递归公式。

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