目录
矩阵乘法秘籍
现在我们有2个矩阵,记作A ,B
其中A矩阵的长宽为N * M B矩阵的长宽为 M * P 那么C矩阵 = A * B,C矩阵的长度就是N * P
?你没有弄懂,没有关系,我们上例子!
A = -1 5 6 B = 1 2
8 -2 -3 -1 -3
4 -1
A的长度就是2 * 3 B就是 3* 2
那么他们相乘得出来的C是个2 * 2的,那么这究竟是怎么算的呢?
给你一个公式 C[i][j] = sigma(A[i][k] * B[k][j]) k的范围自然就是 1 - M 也就是 1 - 3了
我们这样记一个矩阵
C = C11 C12
C21 C22
我们的C11 = A[1][1] * B[1][1] + A[1][2] * B[2][1] + A[1][3] * B[3][1] = 18
C12 = A[1][1] * B[1][2] + A[1][2] * B[2][2] + A[1][3] * B[3][2] = -23
另外的两个我就不用说了吧,大家可能对这个公式一下子不能熟悉,其实大家可以根据 i j不变 k变得特点多观察观察
这样其实对于后面的矩阵加速的优化会很有帮助!
至于怎么实现,这个相信你们就肯定会吧!
矩阵加速入门
首先我们来看一看一个递推式 F[N] = F[N - 1] + F[N - 2] F[1] = F[2] = 1
现在我告诉你 N = 2147483647 怎么办
我给你一个提示 将A矩阵看作一个1 * 2的,A11表示F[N-2] A12表示F[N-1] 那么我们怎么一步步转化将N扩大?
也就是一个B矩阵,应该是怎么样的,才能使得A*B = C
C这个矩阵就从A的 F[N - 2] F[N - 1] 变成了 F[N - 1] F[N]
你肯定有一点点懵逼,不要着急
我们根据矩阵乘法,这样想,C11 在A的基础上 没有A11,但是有A12
也就是C11 = A12
这个大家可以懂吧,至于C12,既有A11,也有A12, 就是说C12 = A11 + A12
大家再想一想
A = F[N - 2] F[N - 1]
C = F[N - 1] F[N]
C11 = A12 C12 = A11 + A12
很明显了,我们怎么建造这个B矩阵呢
C11只有1个A12,所以就是 0 1 (第一个数0表示没有A11 第2个数1表示有A12)
C12有1个A11 1个A12 所以就是 1 1
然后我们排列一下,根据上面的矩阵乘法公式
B = 0 1 这里要注意一下,并不是第一排的0 1表示C11,而是第一列的0 1 表示C11
1 1
我们就发现了乘以n - 2 个B再乘以边界,就得到了F[N]
B^n-2 就可以用快速幂,大家就可以把O N 变成 O logn
我呢也就解释解释,代码下面有,自己去看看吧!其他的题目我没给哈,最好自己去打!
矩阵加速基础
现在我们在上一题的基础上,要求F[1] - F[N]的前缀和,又怎么办呢?
我再提示一下,A矩阵自然要有3个数了,也就是1个 1 * 3 的!
这里3个数有很多种表示的方法,所以大家也不要局限于我的方法哦!
为了让大家思考,我再后面才公布出了方法,所以这里就插入了另外的一个知识,大家不要以为没有哈!
矩阵加速巩固
我们不是说了嘛,就是入门的问题,把A11看作F[N-2] A12看作F[N-1],上面的基础也说了不止一种,你想到了其他方法吗?
我敢肯定,很多人并没有去想这个问题!
大家如果想巩固矩阵加速,就要多思考,用多种方法来巩固你的理解!
为了让大家思考,所以我又插入了另外的,为了让大家思考嘛!大家不要辜负我的好意,害你自己就不要怪我了!
矩阵加速提升
现在又有另外的一个题目 F[1] = F[2] = F[3] = 1 F[N] = F[N - 3] + F[N-1]
建议大家先看一看矩阵加速基础的题目,这里只是给你一个预告!
矩阵加速初级
好了,我们回到基础的问题,现在我们就来公布A11 A12 A13表示什么
我们把A11 表示S[N-2](F[1] + ...... F[N-2]前缀和)
A12 表示 F[N-2]
A13 表示 F[N-1]
那么C11 转化递推自然应该是S[N-1]了 有A11 没有A12 有A13
C12 应该是F[N-1] 自然就只有A13
C13 应该是F[N] 自然就有A12 A13 了
B = 1 0 0
0 0 1
1 1 1
注意啊,我说了C11 在B中是第一列,不要以为是第一行了啊!
我就不用说了,自己去看代码!
矩阵加速中级
我们来解决矩阵巩固的题目!
我们现在把A11 => F[N-1] A12 => F[N-2]
C11 => F[N] = > 1 1 C12 => F[N-1] = > 1 0
B = 1 1
1 0
大家肯定说其实是差不多的,多种方法还是要好一点的哈!
矩阵加速突破
我们现在想一想矩阵加速基础有没有其他方法呢?加油!
矩阵加速拔高
我们来解决提升的问题
A11 = > F[N-3] A12 = > F[N-2] A13 => F[N-1]
C11 = > F[N-2] = > 0 1 0
C12 = > F[N-1] = > 0 0 1
C13 = > F[N] = > 1 0 1
B =0 0 1
1 0 0
0 1 1
矩阵加速终极
我们来解决突破!
自然我们可以这样
A11 = > S[N-1] A12 = > F[N-2] A13 = > F[N-1]
C11 = > S[N] = > 1 1 1
C12 = > F[N-1] = > 0 0 1
C13 = > F[N] = > 0 1 1
B = 1 0 0
1 0 1
1 1 1
矩阵加速运用
现在我们假设 F[1] = Q F[2] = W F[N] = F[N-2] * F[N-1]
那么怎么求F[N]啊! 上面的N都是 1 <= N <= 2147483647
矩阵加速理解
其实我们看了这么多,都发现了矩阵加速的DP只有+号,那么*是否可以呢?
如果DP的方程式有MIN MAX 是否可以呢?
如果f[i]表示n为i的答案的话,f[i]=f[i−1]∗2+f[i−3]∗2−f[i−5]
啊!!!n巨大?矩阵乘法!
需要保存5个东西,准备好5*5的矩阵
矩阵加速博思
大家想一想,二维可以用矩阵加速吗? 这个问题也是困扰了我多时,为了更深刻的了解矩阵加速,我们可以尝试去想一想这个问题......
矩阵加速登阶
我们来解决运用的题目。
其实,上面也给出了一个问题 有*号的DP可不可以用矩阵加速,这里我们可以稍微提及一下理解的问题
大家也发现了,运用的题目就是一个有*号的DP,显然你想了很久,至少不能直接用矩阵加速!
所以这种有*号的是可能会无法直接矩阵加速的!
为什么是可能,等会揭晓!
我们来打一下草稿!
F[1] = A
F[2] = B
F[3] = AB
F[4] = AB^2
F[5] = A^2B^3
F[6] = A^3B^5
F[4] = A^5B^8
就不用我说怎么做了吧,就是指数啊,不就是和入门的规律一样嘛!再用快速幂就可以了!
矩阵加速出师
对于理解的题目,我们这样来 A11 = F[i-1] A12 = F[i - 2] 一共有A15 后面表示什么你还看不出来?
自己再想一想吧!我就给出B的矩阵了!
[2,1,0,0,0]
[0,0,1,0,0]
[2,0,0,1,0]
[0,0,0,0,1]
[-1,0,0,0,0]
完美解决!
但是这里有*号啊,为什么这个可以,而运用的题目就不可以呢?
矩阵加速精英
我们来看看这个题目
- n 为奇数时:
- n 为偶数时:
这里有两个DP式,怎么用矩阵加速呢?
矩阵加速反思
我们来思考博思的问题。
其实二维是可以的,大家也许会很苦恼,二维的情况肯定比一维多得去了,怎么就可以呢,再下面我会解释,并且把出师的遗留问题一起解决!
矩阵加速大佬
我们来解决精英的题目,请看下面!
假设 n 为奇数,那么 ,得到的 n-1 必定是偶数
于是有:
同理,假设 n 为偶数,那么 ,得到的 n-1 必定是奇数
于是有:
那么,无论 n 为奇还是为偶, 一定成立
矩阵加速秘籍
其实,为什么*号有时候不可以,二维有时候也可以用矩阵加速!
你不管他怎么变,怎么搞,只要满足这样一个性质,从A 变为 C B是固定的,那么就可以矩阵加速!
运用的题目之所以不能直接矩阵加速,是因为B不是一定的!
你也许会想到这样的一个B (大家不用往上面看了,下面将题目复制了下来)
现在我们假设 F[1] = Q F[2] = W F[N] = F[N-2] * F[N-1]
那么怎么求F[N]啊! 上面的N都是 1 <= N <= 2147483647
A11 = F[N-2] A12 = F[N-1]
C11 = > F[N-1] => 0 1
C12 = > F[N] = F[N-1] 0 || 0 F[N-2]
这个自然是正确的,但是F[N-1] F[N-2] 再变化啊,你就不能用矩阵快速幂了!
而理解的题目中,f[i]=f[i−1]∗2+f[i−3]∗2−f[i−5] 中,乘的数是一定的,就是2,所以可以用矩阵加速!
另外,如果有MIN ,MAX 其实是不影响的,只要满足上面的条件,都是可以的(大不了比较一下大小)
也就是这个DP,所有的转移,B是一定的,那么就可以!
如果方程有多个,可以先变成一个
如果找不到一定的B,就要靠你去间接找固定的B了!
另外矩阵加速有很多方法,而且有时候B甚至是通过各种奇葩奥秘的方法解出的,我自然初学肯定也不能完全掌握吧,大家自行努力吧!
矩阵加速资源
这只是我认为一个还比较可以的,当然有更好的也欢迎大家推荐!
https://blog.youkuaiyun.com/u011815404/article/details/88842009
矩阵加速代码
其实刚开始是不想有代码的,想让大家自己去打,自己去看,但是后面有人反馈最好还是给一个,我就给一个吧!
这个是入门的代码,大家也可以借这个快速理解!
另外这个m只是一个模数,不妨碍大家看吧!
#include <cstdio>
#define reg register
int n, m;
struct node{
long long x, y, c[5][5];
node operator * (const node &b){
node d;
d.x = x;
d.y = b.y;
for(reg int i = 1; i <= d.x; i++){
for(reg int j = 1; j <= d.y; j++){
d.c[i][j] = 0;
for(reg int k = 1; k <= y; k++){
d.c[i][j] = (d.c[i][j] + c[i][k] * b.c[k][j]) % m;
}
}
}
return d;
}
}beg;
inline void slove(){
if(n < 3){
printf("1\n");
return ;
}
int csq = n - 2;
node t, ans;
ans.c[1][1] = ans.c[2][2] = 1;
ans.c[1][2] = ans.c[2][1] = 0;
ans.x = ans.y = t.x = t.y = 2;
t.c[1][1] = 0;
t.c[1][2] = t.c[2][1] = t.c[2][2] = 1;
while(csq){
if(csq & 1){
ans = ans * t;
}
t = t * t;
csq >>= 1;
}
beg = beg * ans;
printf("%lld\n", beg.c[1][2]);
}
int main(){
beg.x = 1;
beg.y = 2;
beg.c[1][1] = beg.c[1][2] = 1;
scanf("%d%d", &n, &m);
slove();
return 0;
}
矩阵加速留言
最后还是大家感兴趣的话,别忘了点赞,关注,转发......不当或错误之处欢迎大家指出!(不要钻牛尖)