矩阵加速

本文深入讲解了矩阵加速的各种技巧,包括矩阵乘法的基本原理、如何应用于动态规划问题中,特别是针对复杂的递推式进行优化的方法。同时探讨了矩阵加速在不同情况下的适用性和局限性。

目录

矩阵乘法秘籍

矩阵加速入门

矩阵加速基础

矩阵加速巩固

矩阵加速提升

矩阵加速初级

矩阵加速中级

矩阵加速突破

矩阵加速拔高

矩阵加速终极

矩阵加速运用

矩阵加速理解

矩阵加速博思

矩阵加速登阶

矩阵加速出师

矩阵加速精英

矩阵加速反思

矩阵加速大佬

矩阵加速秘籍

矩阵加速资源

矩阵加速代码

矩阵加速留言


矩阵乘法秘籍

现在我们有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 为奇数时:f[n] = f[n-1] * 2 + 1
  • n 为偶数时:f[n] = f[n-1] * 2

这里有两个DP式,怎么用矩阵加速呢?

矩阵加速反思

我们来思考博思的问题。

其实二维是可以的,大家也许会很苦恼,二维的情况肯定比一维多得去了,怎么就可以呢,再下面我会解释,并且把出师的遗留问题一起解决!

矩阵加速大佬

我们来解决精英的题目,请看下面!

假设 n 为奇数,那么 f[n] = f[n-1] * 2 + 1,得到的 n-1 必定是偶数

于是有:f[n] = f[n-1] + f[n-2] * 2 + 1

同理,假设 n 为偶数,那么 f[n] = f[n-1] * 2,得到的 n-1 必定是奇数

于是有:f[n] = f[n-1]+ f[n-2] * 2+1

那么,无论 n 为奇还是为偶,f[n] = f[n-1]+ f[n-2] * 2+1 一定成立

矩阵加速秘籍

其实,为什么*号有时候不可以,二维有时候也可以用矩阵加速!

你不管他怎么变,怎么搞,只要满足这样一个性质,从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;
}

矩阵加速留言

最后还是大家感兴趣的话,别忘了点赞,关注,转发......不当或错误之处欢迎大家指出!(不要钻牛尖)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值