1.通用模板:矩阵快速幂
前几天写过一篇矩阵快速幂的一种解法,但是当时只是初学,所以用了当时我更好理解的方法去做。那个解法需要调用两个很相像的函数,而且容易造成紊乱,也不利于矩阵快速幂的推广,所以在观摩了其他大佬的代码后对之前的代码进行了改进。
先把题目贴出来:
题目背景
矩阵快速幂
题目描述
给定 n×n 的矩阵 A,求
。
输入格式
第一行两个整数 n,k 接下来 n 行,每行 n 个整数,第 i 行的第 j 的数表示
。
输出格式
输出 A^kAk
共 nn 行,每行 nn 个数,第 ii 行第 jj 个数表示
,每个元素对 10^9+7109+7 取模。
输入输出样例
输入 #1复制
2 1 1 1 1 1输出 #1复制
1 1 1 1说明/提示
【数据范围】
#include <iostream> #include <algorithm> #include <cstdio> using namespace std; typedef long long LL; //或者#define LL long long #define N 105 const int md = 1e9 + 7; LL i, j, k; LL m, n, t;//必须定义为长整型,否则全错 //1.使用结构体定义矩阵和矩阵清零的函数,方便后续使用 struct Matrix//我之前的写法没有定义矩阵,也没重载乘法运算符,不能让两个二维数组直接赋值,但是可以让两结构体直接赋值 { LL s[N][N]; void clear() { for (i = 0; i < n; i++) { for (j = 0; j < n; j++) { s[i][j] = 0;//矩阵初始化 } } return; } }base;//最开始的矩阵在这里就可以定义了,不在前面定义的话,后面的函数可能会找不到base,然后出错 //2.重载矩阵乘法,方便后续计算,同样使用*只是不能使用*= Matrix operator * (Matrix a, Matrix b) { Matrix tmp; tmp.clear(); for (i = 0; i < n; i++) { for (j = 0; j < n; j++) { for (k = 0; k < n; k++) { tmp.s[i][j] += a.s[i][k] * b.s[k][j] % md; tmp.s[i][j] %= md; } } } return tmp; } //3.然后就是快速幂的解法了 Matrix MFPow() { Matrix res; res.clear(); for (i = 0; i < n; i++) { res.s[i][i] = 1; }//初始化为单位矩阵 while (m) { if (m & 1) { res = res * base; } base = base * base; m >>= 1; } return res; } int main() { Matrix eRes; cin >> n >> m; for (i = 0; i < n; i++) { for (j = 0; j < n; j++) { cin >> base.s[i][j]; } } eRes = MFPow(); for (i = 0; i < n; i++) { for (j = 0; j < n; j++) { cout << eRes.s[i][j]<<' '; } cout << endl; } return 0; }
2.普通斐波那契数列的解法
题目背景
大家都知道,斐波那契数列是满足如下性质的一个数列:
题目描述
请你求出
的值。
输入格式
一行一个正整数 n
输出格式
输出一行一个整数表示答案。
输入输出样例
输入 #1复制
5输出 #1复制
5输入 #2复制
10输出 #2复制
55说明/提示
【数据范围】
对于 60% 的数据,1≤n≤92;
对于 100% 的数据,。
题解:构造一个斐波那契数列的1*2矩阵: ,;
根据矩阵的知识,我们可以构建这样的 一个2*2的base矩阵
然后我们从比较简单的项分析一下:
所以初始矩阵res可以定义为,(其实也可以定义为单位矩阵吗、,但是这么解释之后的推广就能更好地理解了)
最后的代码:
#include<iostream>
#include<algorithm>
#include <map>
#include <unordered_map>
#include <queue>
#include<iostream>
#include<algorithm>
#include <map>
#include <unordered_map>
#include <queue>
#include<cstdio>
#include<string>
using namespace std;
#define LL long long
#define Md 1000000007
#define N 100
LL i, j, k;
LL n, m;
struct Matrix
{
LL s[N][N];
void clear()
{
for (i = 0; i < 2; i++)
{
for (j = 0; j < 2; j++)
{
s[i][j] = 0;
}
}
return ;
}
}base;//在前面定义,否则后面找不到
Matrix operator * (Matrix a, Matrix b)
{
Matrix tmp;
tmp.clear();
for (i = 0; i < 2; i++)
{
for (j = 0; j < 2; j++)
{
for (k = 0; k < 2; k++)
{
tmp.s[i][j] += a.s[i][k] * b.s[k][j] % Md;
tmp.s[i][j] %= Md;
}
}
}
return tmp;
}
Matrix FPow(LL m)
{
Matrix res;
res.clear();
/*for (i = 0; i < 2; i++)
{
res.s[i][i] = 1;
}*/
res.s[0][0]=1;
res.s[0][1]=1;
while (m)
{
if (m & 1)
{
res = res * base;
}
base = base * base;
m >>= 1;
}
return res;
}
int main()
{
Matrix ERes;
cin >> n;
if (n <= 2) cout << 1;
base.s[0][0] = base.s[0][1] = base.s[1][0] = 1;
m = n - 2;//如果初始矩阵res定义为单位矩阵,m=n-1;
if (n > 2)
{
ERes=FPow(m);
cout << ERes.s[0][0];
}
return 0;
}
给自己挖个坑,斐波那契数列的一些推广的题目等之后再写