EVERYTHING HAPPENS FOR THE BE|

wnsyou

园龄:2年4个月粉丝:19关注:16

2023-08-05 11:51阅读: 104评论: 0推荐: 0

矩阵运算

矩阵运算

OI-wiki Link

众所周知,数是可以进行加减乘除的,那矩阵为啥不可以呢?

假设现在我们有两个矩阵 AB,矩阵大小分别为 n×mx×y,矩阵元素对 mod 取模。

const int N = 110, mod = 1e9 + 7; // 矩阵大小和模数
struct matrix {
int a[N][N], n, m; // 存储矩阵和矩阵大小
} ;

基本运算

矩阵加法

A+B=C

要求:n=x 并且 m=y

其实很简单,就是一一对应着加就行,即对于 1in,1jmCi,j=Ai,j+Bi,j

所以 C 的大小为 n×m,矩阵减法同。

性质

  • 交换律:明显满足,即 A+B=B+A
  • 结合律:明显满足,即 A+B+C=A+(B+C)

单位矩阵

明显,就是一个大小为 n×m 的全 0 矩阵。

矩阵加法 Code

时间复杂度:O(n×m)

matrix operator + (matrix y) { // 重载运算符 +
matrix z;
z.n = n, z.m = m;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
z.a[i][j] = a[i][j] + y.a[i][j];
return z;
}

矩阵乘法

A×B=C

要求:m=x

公式:对于 1in,1jy:

Ci,j=1kmAi,k×Bk,j

似乎看起来没啥用?因为它是在某些特定方面可以进行时间优化(例如用 O(8logn) 的时间复杂度求出斐波那契数列的第 n 项),所以一般就是把它和其他知识点捆绑起来(例如矩阵乘法优化 dp 等),单独拎出来出的题目很少(大多都是板子)。

性质

  • 交换律:不满足!
    • n=y,交换以后还能乘法,但矩阵大小会变为 m×x,与原矩乘后答案不同。
    • 当然也有可能 ny,这样交换以后连矩乘的基本要求都无法满足。
  • 结合律:满足,设还有一个矩阵 C,大小为 y×zA×B×C=D,则 D 大小为 n×z,而 A×(B×C)=A×E(大小为x×z)=D
  • 分配律:明显满足,设还有一个矩阵 C,大小为 y×z,即 A×(B+C)=A×B+A×C

单位矩阵

Link

提到矩乘,就不得不提到它的单位矩阵。

单位矩阵定义:若这个矩阵乘任意一个矩阵 C,得到的结果都等于 C,则这个矩阵为单位矩阵。

观察式子,容易推出:当一个大小为 n×n 的矩阵除了主对角线(从左上到右下)以外的数为 1,其他都为 0 时,它就是一个可以作为所有大小为 n×m 的矩阵的单位矩阵。

时间复杂度:O(x×y)

void Clear (int x, int y, int f) { // 把矩阵大小设为 x * y,矩阵元素都为 f
n = x, m = y;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
a[i][j] = f;
}
void Unit (int x, int y) { // 构造单位矩阵
Clear(x, y, 0); // 先清空
for (int i = 1; i <= n; i++)
a[i][i] = 1; // 只有主对角线为 1
}

矩阵乘法 Code

时间复杂度:O(n×m×y)

matrix operator * (matrix y) { // 重载运算符 *
matrix z;
z.n = n, z.m = y.m;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= y.m; j++) {
z.a[i][j] = 0;
for (int k = 1; k <= m; k++)
z.a[i][j] = (z.a[i][j] + 1ll * a[i][k] * y.a[k][j] % mod) % mod; // 套公式
}
return z;
}

矩阵除法

AB=C

要求:同矩阵乘法。

由于浮点数不可以取模,数里面除法取模等于乘上除数的逆,所以矩阵除法同矩阵除法,不过是把 Bi,j 变成 Bi,j 在模 mod 意义下的逆。

矩乘与它的特殊运算和应用

P3390 矩乘快速幂

给定一个矩阵 A,大小为 n×m,一个指数 k 和一个模数 mod,求 Ak % mod

要求:矩阵的大小必须为 n×n

既然矩乘有结合律,那么就可以考虑使用类似于整数快速幂的方法以 O(logk) 的方式求出 Ak,由于一次矩阵乘法需要 O(n3),所以总时间复杂度为 O(n3logk)

矩乘快速幂 Code

时间复杂度:O(n3logk)

matrix MATqmod (matrix x, ll y) { // 矩阵乘法快速幂
matrix sum;
sum.Unit(x.n, x.m); // 初始化为单位矩阵
while (y) sum = (y & 1 ? sum * x : sum), x = x * x, y >>= 1;
return sum;
}

P1349 广义斐波那契数列

P1962 斐波那契数列

广义的斐波那契数列是指形如 an=p×an1+q×an2 的数列。

今给定数列的两系数 pq,以及数列的最前两项 a1a2,另给出两个整数 nm,试求数列的第 nanmodm

Fi 表示当前情况下斐波那契数列第 i 项的值。

观察一下,把相邻两项构成一个矩阵,即要从 fi=[Fi,Fi1] 通过操作变为 fi+1=[Fi+1,Fi]=[p×Fi+q×Fi1,Fi],考虑用矩乘完成。

要能与 [Fi,Fi1] 做矩乘,就需要一个大小为 2×k 的矩阵,又因为矩乘之后的矩阵仍然大小为 1×2,所以 k=2,即要求一个矩阵 A=[a,bc,d],使得 A×fi=fi+1

套入公式,就是要求 {a×Fi+c×Fi1=p×Fi+q×Fi1b×Fi+d×Fi1=Fi,可以推出 {a=pb=1c=qd=0,现在要求 Fn,初始矩阵为[a2,a1],每次乘矩阵 A=[p,1q,0] 后都会使矩阵两项下标加 1,特判 n=1 的情况(答案为 a1),那么答案就是 [a2,a1]×An2 取第一个元素即可,需要矩阵乘法快速幂。

普通的其实就相当于 a1=a2=p=q=1

Code

matrix c, d;
int n, mod;
c.Clear(2, 2, 0), d.Clear(1, 2, 0);
cin >> c.a[1][1] >> c.a[2][1] >> d.a[1][2] >> d.a[1][1] >> n >> mod;
if (n == 1) {
cout << d.a[1][2];
return 0;
}
c.a[1][2] = 1, d = d * qmod(c, n - 2);
cout << d.a[1][1];

完整代码

点击查看最新代码
#include <bits/stdc++.h>
#define _1 (__int128)1
using namespace std;
using ll = long long;
void FileIO (string s) {
freopen((s + ".in").c_str(), "r", stdin);
freopen((s + ".out").c_str(), "w", stdout);
}
const int mod = 1e9 + 7, MATsize = 110; // 矩阵大小和模数
struct matrix {
int a[MATsize][MATsize], n, m; // 存储矩阵和矩阵大小
void Clear (int x, int y, int f) { // 把矩阵大小设为 x * y,矩阵元素都为 f
n = x, m = y;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
a[i][j] = f;
}
void Unit (int x, int y) { // 构造单位矩阵
Clear(x, y, 0); // 先清空
for (int i = 1; i <= n; i++)
a[i][i] = 1; // 只有主对角线为 1
}
matrix operator + (matrix y) { // 重载运算符 +
matrix z;
z.n = n, z.m = m;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
z.a[i][j] = a[i][j] + y.a[i][j];
return z;
}
matrix operator * (matrix y) { // 重载运算符 *
matrix z;
z.n = n, z.m = y.m;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= y.m; j++) {
z.a[i][j] = 0;
for (int k = 1; k <= m; k++)
z.a[i][j] = (z.a[i][j] + 1ll * a[i][k] * y.a[k][j] % mod) % mod; // 套公式
}
return z;
}
} ;
matrix MATqmod (matrix x, ll y) { // 矩阵乘法快速幂
matrix sum;
sum.Unit(x.n, x.m); // 初始化为单位矩阵
while (y) sum = (y & 1 ? sum * x : sum), x = x * x, y >>= 1;
return sum;
}
signed main () {
ios::sync_with_stdio(0), cin.tie(0);
// FileIO("");
return 0;
}
点击查看无注释代码
#include <bits/stdc++.h>
#define _1 (__int128)1
using namespace std;
using ll = long long;
void FileIO (string s) {
freopen((s + ".in").c_str(), "r", stdin);
freopen((s + ".out").c_str(), "w", stdout);
}
const int mod = 1e9 + 7, MATsize = 110;
struct matrix {
int a[MATsize][MATsize], n, m;
void Clear (int x, int y, int f) {
n = x, m = y;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
a[i][j] = f;
}
void Unit (int x, int y) {
Clear(x, y, 0);
for (int i = 1; i <= n; i++)
a[i][i] = 1;
}
matrix operator + (matrix y) {
matrix z;
z.n = n, z.m = m;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
z.a[i][j] = a[i][j] + y.a[i][j];
return z;
}
matrix operator * (matrix y) {
matrix z;
z.n = n, z.m = y.m;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= y.m; j++) {
z.a[i][j] = 0;
for (int k = 1; k <= m; k++)
z.a[i][j] = (z.a[i][j] + 1ll * a[i][k] * y.a[k][j] % mod) % mod;
}
return z;
}
} ;
matrix MATqmod (matrix x, ll y) {
matrix sum;
sum.Unit(x.n, x.m);
while (y) sum = (y & 1 ? sum * x : sum), x = x * x, y >>= 1;
return sum;
}
signed main () {
ios::sync_with_stdio(0), cin.tie(0);
// FileIO("");
return 0;
}

本文作者:wnsyou の blog

本文链接:https://www.cnblogs.com/wnsyou-blog/p/matrix.html

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   wnsyou  阅读(104)  评论(0编辑  收藏  举报
  1. 1 勝利への道 安藤浩和
  2. 2 Minecraft’s End Eric Fullerton
  3. 3 月光曲完整版 贝多芬 云熙音乐
  4. 4 平凡之路 (Live版) 朴树
  5. 5 Minecraft C418
  6. 6 Paradise NiziU
  7. 7 叫我,灰原哀 龙大人不喷火
  8. 8 心机之蛙,一直摸你肚子 ——《名侦探柯南》原创同人曲 炊饭,叶辞樱,温海,寒砧,南柯柯,小茜玛姬,盛姝,阿崔Ac,贝壳初,千湛,兮茶子DaYu,乔慕,黎鹿北,起千温卿,遮阳伞,曲悠
  9. 9 战 歌 此去经年
平凡之路 (Live版) - 朴树
00:00 / 00:00
An audio error has occurred, player will skip forward in 2 seconds.

作词 : 朴树/韩寒

作曲 : 朴树

编曲 : 朴树

徘徊着的 在路上的

你要走吗 via via

易碎的 骄傲着

那也曾是我的模样

沸腾着的 不安着的

你要去哪 via via

谜一样的 沉默着的

故事你真的在听吗

我曾经跨过山和大海

也穿过人山人海

我曾经拥有着的一切

转眼都飘散如烟

我曾经失落失望失掉所有方向

直到看见平凡才是唯一的答案

当你仍然

还在幻想

你的明天 via via

她会好吗 还是更烂

对我而言是另一天

我曾经毁了我的一切

只想永远地离开

我曾经堕入无边黑暗

想挣扎无法自拔

我曾经像你像他像那野草野花

绝望着也渴望着

也哭也笑平凡着

jia do

la so

哦~

向前走 就这么走

就算你被给过什么

向前走 就这么走

就算你被夺走什么

向前走 就这么走

就算你会错过什么

向前走 就这么走

就算你会

我曾经跨过山和大海

也穿过人山人海

我曾经拥有着的一切

转眼都飘散如烟

我曾经失落失望失掉所有方向

直到看见平凡才是唯一的答案

我曾经毁了我的一切

只想永远地离开

我曾经堕入无边黑暗

想挣扎无法自拔

我曾经像你像他像那野草野花

绝望着 渴望着 也哭也笑平凡着

我曾经跨过山和大海

也穿过人山人海

我曾经问遍整个世界

从来没得到答案

我不过像你像他像那野草野花

冥冥中这是我 唯一要走的路啊

时间如烟

如此这般

明天已在 via via

风吹过的 路依然远

你的故事讲到了哪

加载中…

{{tag.name}}

{{tran.text}}{{tran.sub}}
无对应文字
有可能是
{{input}}
尚未录入,我来提交对应文字
评论
收藏
关注
推荐
深色
回顶
收起
点击右上角即可分享
微信分享提示