首页 > 其他分享 >矩阵乘法与快速幂

矩阵乘法与快速幂

时间:2024-03-12 16:23:21浏览次数:19  
标签:log int 矩阵 times ans 快速 乘法

矩阵乘法

  • 定义:

    给定矩阵 \(A\) 规模为 \(n\times m\) ,矩阵 \(B\) 规模为 \(m\times p\) ,定义 \(A\times B=C\) ,矩阵 \(C\) 规模为 \(n\times p\) ,满足:

    \[c_{ij}=\sum_{k=1}^ma_{ik}b_{kj} \]

    记住一个口诀:左行右列

  • 注意:

    对于矩阵乘法,满足乘法结合律和乘法分配律,不满足乘法交换律。

    举个例子:

    \(A=\)

    image

    \(B=\)

    image

    那么 \(A\times B=\)

    image

    \(B\times A=\)

    image

    可见 \(A\times B\neq B\times A\) 。

  • 代码实现:

for(int i=1;i<=n;i++)
    for(int j=1;j<=p;j++)
        for(int k=1;k<=m;k++)
            c[i][j]=a[i][k]*b[k][j];

快速幂

  • 定义:

    在 \(O(\log(n))\) 的时间内求出 \(x^n\) 。

  • 原理:

    已知: 若 \(a+b=c\) ,则 \(x^a\times x^b=x^c\) 。

    那么将 \(n\) 转化为二进制,举个例子:

    \[x^{(13)_{10}}=x^{(1101)_2}=x^8\times x^4\times x^1 \]

    因为 \(n\) 有 \(\log(n)\) 个二进制位,所以在知道 \(x^1,x^2,x^3,…,x^{2^{\log(n)}}\) 前提下,即可在 \(O(\log(n))\) 的时间内求出 \(x_n\) 。

    问题转化位如何让求 \(x^1,x^2,x^3,…,x^{2^{\log(n)}}\),而在这个序列中,满足:

    \[x^{2^k}=\begin{cases} x&k=0\\ (x^{2^{k-1}})^2&k\geq 1\\ \end{cases}\]

    于是就同样可以在 \(O(\log(n))\) 的时间内,求出 \(x^1,x^2,x^3,…,x^{2^{\log(n)}}\) 。

    得出结论:计算 \(x^n\) ,只需将 \(n\) 的二进制位为 \(1\) 的整系数幂乘起来即可。

    于是发现,上述所有步骤均可以在 \(O(\log(n))\) 的复杂度上递推实现。

  • 代码实现:

    1. 计算 \(a^b\) 。

      int qpow(int a,int b)
      {
          int ans=1;
          for(;b;b>>=1)
          {
              if(b&1) ans*=a;
              a*=a;
          }
          return ans;
      }
      
    2. 计算 \(a^b\bmod P\)

      int qpow(int a,int b,int P)
      {
          int ans=1;
          for(;b;b>>=1)
          {
              if(b&1) (ans*=a)%=P;
              (a*=a)%=P;
          }
          return ans;
      }
      
    3. 根据费马小定理,$a^{P-1}≡1\pmod P $ ,前提,\(P\) 为质数。

      那么当 \(P\) 为质数时,可通过 \(a^{P-2}\bmod P\) 求出 \(a^{-1}\bmod P\) ,即 \(a\) 的乘法逆元。

      可用快速幂实现。

矩阵快速幂

  • 定义:

    基于基本的快速幂,将乘法运算扩展为矩阵乘法运算。

    由于矩阵乘法复杂度 \(O(n^3)\) ,快速幂复杂度 \(O(\log(n))\) ,所以矩阵快速幂复杂度为 \(O(n^3\log(n))\) 。

  • 代码实现:

    此处代码仅为样例,矩阵 \(A,B\) 规模均为 \(2\times 2\) ,根据不同题的需要进行更改。

    导入概念,如果矩阵 \(A\) 对角线上元素均为 \(1\) ,其余均为 \(0\) ,则 \(A\times B=B\) 。

    void qpow(int b)
    {
        memset(ans,0,sizeof(ans));
        for(int i=1;i<=2;i++)
            ans[i][i]=1;//int ans=1;
        for(;b;b>>=1)
        {
            if(b&1)
            {
                for(int i=1;i<=2;i++)   
                    for(int j=1;j<=2;j++)
                        for(int k=1;k<=2;k++)
                            (c[i][j]+=(ans[k][j]*a[i][k])%P)%P;
                for(int i=1;i<=2;i++)
                    for(int j=1;j<=2;j++)   
                        ans[i][j]=c[i][j],c[i][j]=0;
            }//if(b&1) ans*=a;
            for(int i=1;i<=2;i++)
                for(int j=1;j<=2;j++)
                    for(int k=1;k<=2;k++)
                        (c[i][j]+=(a[i][k]*a[k][j])%P)%P;
            for(int i=1;i<=2;i++)
                for(int j=1;j<=2;j++)
                    a[i][j]=c[i][j],c[i][j]=0;//a*=a;
        }
    }
    
  • 例题:

    • \(Fibonacci\) 第 \(n\) 项

      • 题意:

        \[f_x=\begin{cases} 1&x\in\{1,2\}\\ f_{x-1}+f_{x-2}&x \geq 3\\ \end{cases}\]

        给定一个 \(n\) ,求 \(f_n\) 。

        \(n\leq 2e9\) 。

      • 解法:

        \[f_n=1\times f_{n-1}+1\times f_{n-2} \]

        \[f_{n-1}=1\times f_{n-1}+0\times f_{n-2} \]

        通过矩阵乘法,可将其转化为:

        image

        由此即可通过矩阵快速幂和矩阵乘法求出答案。

        点击查看代码
        #include<bits/stdc++.h>
        #define int long long 
        #define endl '\n'
        using namespace std;
        const int N=10;
        template<typename Tp> inline void read(Tp&x)
        {
            x=0;register bool z=true;
            register char c=getchar();
            for(;c<'0'||c>'9';c=getchar()) if(c=='-') z=0;
            for(;'0'<=c&&c<='9';c=getchar()) x=(x<<1)+(x<<3)+(c^48);
            x=(z?x:~x+1);
        }
        int n,P,ans[N][N],c[N][N],a[N][N];
        void qpow(int b)
        {
            for(;b;b>>=1)
            {
                if(b&1)
                {
                    for(int i=1;i<=2;i++)   
                        for(int j=1;j<=2;j++)
                            for(int k=1;k<=2;k++)
                                (c[i][j]+=(ans[k][j]*a[i][k])%P)%P;
                    for(int i=1;i<=2;i++)
                        for(int j=1;j<=2;j++)   
                            ans[i][j]=c[i][j],c[i][j]=0;
                }
                for(int i=1;i<=2;i++)
                    for(int j=1;j<=2;j++)
                        for(int k=1;k<=2;k++)
                            (c[i][j]+=(a[i][k]*a[k][j])%P)%P;
                for(int i=1;i<=2;i++)
                    for(int j=1;j<=2;j++)
                        a[i][j]=c[i][j],c[i][j]=0;
            }
        }
        signed main()
        {
            #ifndef ONLINE_JUDGE
            freopen("in.txt","r",stdin);
            freopen("out.txt","w",stdout);
            #endif
            read(n),read(P);
            a[1][1]=1;
            a[2][1]=1;
            a[1][2]=1;
            a[2][2]=0;
            for(int i=1;i<=2;i++)
                ans[i][i]=1;
            qpow(n-2);
            cout<<(ans[1][1]+ans[1][2])%P;//实则为 1*ans[1][1]+1*ans[1][2],1省去,参考矩阵乘法定义。
        }
        
    • 矩阵加速(数列)

      • 题意:

        与上一道类似的,可理解为稍微变化的 \(Fibonacci\) 第 \(n\) 项。

        \[f_x=\begin{cases} 1&x\in\{1,2,3\}\\ f_{x-1}+f_{x-3}&x \geq 4\\ \end{cases}\]

        给定一个 \(n\) ,求 \(f_n\) 。

        \(n\leq 2e9\) 。

      • 解法:

        也是和上面类似的,可以导出:

        ∵ \(f_n=f_{n-1}+f_{n-3}\)

        \(~~~~f_{n-1}=f_{n-2}+f_{n-4}\)

        \(~~~~f_{n-2}=f_{n-3}+f_{n-5}\)

        ∴ \(f_n=2\times f_{n-3}+1\times f_{n-4}+1\times f_{n-5}\)

        \(~~~~f_{n-1}=1\times f_{n-3}+1\times f_{n-4}+1\times f_{n-5}\)

        \(~~~~f_{n-2}=1\times f_{n-3}+0\times f_{n-4}+1\times f_{n-5}\)

        image

        最后问题在于处理答案。

        这次和上面的不同,上面的每一组就是 \(f_{x}→f_{x+1}\) ,而对于这次而言,\(n\bmod 3\) 的结果不同,统计答案也不同。

        1. \(n\bmod 3=0\) ,对应矩阵中第一行,即 \(ans_{1,1}+ans_{1,2}+ans_{1,3}\) (因为 \(f_1=f_2=f_3=1\) ,所以省去 “\(1\times\)” ,下面不在解释) 。

        2. \(n\bmod 3=2\) ,对应矩阵中第二行,即 \(ans_{2,1}+ams_{2,2}+ans_{2,3}\) 。

        3. \(n\bmod 3=1\) ,对应矩阵中第三行,即 \(ans_{3,1}+ans_{3,2}+ans_{3,3}\) 。

        点击查看代码
        #include<bits/stdc++.h>
        #define int long long 
        #define endl '\n'
        using namespace std;
        const int N=10,P=1e9+7;
        template<typename Tp> inline void read(Tp&x)
        {
            x=0;register bool z=true;
            register char c=getchar();
            for(;c<'0'||c>'9';c=getchar()) if(c=='-') z=0;
            for(;'0'<=c&&c<='9';c=getchar()) x=(x<<1)+(x<<3)+(c^48);
            x=(z?x:~x+1);
        }
        int t,n,ans[N][N],c[N][N],a[N][N];
        void qpow(int b)
        {
            for(;b;b>>=1)
            {
                if(b&1)
                {
                    for(int i=1;i<=3;i++)   
                        for(int j=1;j<=3;j++)
                            for(int k=1;k<=3;k++)
                                (c[i][j]+=(ans[k][j]*a[i][k])%P)%P;
                    for(int i=1;i<=3;i++)
                        for(int j=1;j<=3;j++)   
                            ans[i][j]=c[i][j],c[i][j]=0;
                }
                for(int i=1;i<=3;i++)
                    for(int j=1;j<=3;j++)
                        for(int k=1;k<=3;k++)
                            (c[i][j]+=(a[i][k]*a[k][j])%P)%P;
                for(int i=1;i<=3;i++)
                    for(int j=1;j<=3;j++)
                        a[i][j]=c[i][j],c[i][j]=0;
            }
        }
        signed main()
        {
            #ifndef ONLINE_JUDGE
            freopen("in.txt","r",stdin);
            freopen("out.txt","w",stdout);
            #endif
            read(t);
            while(t--)
            {
                read(n);
                a[1][1]=2,a[1][2]=1,a[1][3]=1;
                a[2][1]=1,a[2][2]=1,a[2][3]=1;
                a[3][1]=1,a[3][2]=0,a[3][3]=1;
                memset(ans,0,sizeof(ans));
                for(int i=1;i<=3;i++)
                    ans[i][i]=1;
                qpow((n-1)/3);
                if(n%3==0) cout<<(ans[1][1]+ans[1][2]+ans[1][3])%P<<endl;
                else if(n%3==2) cout<<(ans[2][1]+ans[2][2]+ans[2][3])%P<<endl;
                else if(n%3==1) cout<<(ans[3][1]+ans[3][2]+ans[3][3])%P<<endl;
            }
        }
        

序言

后面(甚至前面)好多只是都要用到矩阵乘法与矩阵快速幂,所以就来补了。

顺便回顾一下快速幂,\(HEOI2024\) 考场上快速幂板子忘了怎么打了,索性重新推了一遍,好在当时推出来了(于是骗到 \(20pts\) )。

题还没有打完,但是知识点算是搞明白了,加深一下记忆继续打题,以防下面的题不知所措。

标签:log,int,矩阵,times,ans,快速,乘法
From: https://www.cnblogs.com/Charlieljk/p/18068598

相关文章

  • 基于Vue(提供Vue2/Vue3版本)和.Net Core前后端分离、跨平台的快速开发框架
    前言今天大姚给大家推荐一款基于Vue(提供Vue2/Vue3版本)和.NetCore前后端分离、开源免费(MITLicense)、强大、跨平台的快速开发框架,并且框架内置代码生成器(解决重复性工作,提高开发效率),支持移动端(iOS/Android/H5/微信小程序):Vue.NetCore。提高开发生产效率、避免996可以考虑试试这......
  • abc336F 旋转矩阵谜题
    有一个大小为W*H的矩阵,每个格子里分别有1~W*H的某个数字,对应1~W*H的一个排列。每次可以选择大小为(W-1)*(H-1)的子矩阵旋转180度。给定初始状态,问20步以内是否可以将它还原?如果可以,输出最小步数,否则输出-1。3<=H,W<=8;1<=a[i][j]<=H*W;a[i][j]各不相等bfs搜索,由于每一步都......
  • 无法访问GitHub,原因以及快速解决办法(转载)
    转载:无法访问GitHub,原因以及快速解决办法访问GitHub时,总是无法访问:例如出现如下情况:原因分析:一、首先,需要明确的是GitHub本身并没有封锁某些地区的访问。如果无法访问GitHub,很有可能是由于网络层面的问题。可能存在以下问题:DNS是一种用于将网址转换为IP地址的工具,如果你的电......
  • 代码生成器之如何快速生成后端接口?
    前言在现代软件开发中,重复性的增删改查逻辑代码的编写往往非常耗时且容易出错。为了提高开发效率,减少手动维护的成本,代码生成器就成为了一个非常重要的工具,本文小编就将为大家介绍一下如何利用一个开源项目快速生成数据接口。实现方式环境准备技术栈:Java,Spring-Boot,MyBatisPlu......
  • 中考英语首字母快速突破003-2021上海奉贤英语二模-The Trick of '9' and '.99' Pricin
    PDF格式公众号回复关键字:ZKSZM003原文​The“DoubleEleven”ShoppingFestivalisoneofthelargestshoppingfestivalsinChina.Lastyear,thefestivalwentonforelevendays.Alibabaalonesaw498.2billionyuanintrade.​Manypeopleb......
  • 快速排序
    快排属于分治算法;思想:快排的思想是分治我们有一个待排序的数组,长度为n。选定一个基准,将数组分成左右两部分,左边的数小于基准,右边的数大于基准。然后我们分别看分割后左右两部分数组,如果元素个数大于1,就再次分割。直到最后,我们得到了n个数组,每个数组含有1个元素。这n个数组......
  • [牛客]小红走矩阵
    题目思路直接套bfs模板代码#include<bits/stdc++.h>usingnamespacestd;usingll=longlong;constintN=1e3+5,INF=0x3f3f3f3f;structNode{ intx,y,s;}t,t1;chargraph[N][N];boolvis[N][N];queue<Node>q;intdx[4]={0,0,1,1};intdy[4]={-1,1,0......
  • PW2058降压芯片:3.7V至3V快速转换,低功耗设计,外围电路简洁
    概述:在便携式设备日益普及的今天,高效、稳定的电源管理成为了关键。PW2058作为一款恒频、电流模式降压转换器,以其出色的性能和广泛的应用范围,成为了市场上备受瞩目的产品。它集成了主开关和同步整流器,无需额外添加肖特基二极管,即可实现高达96%的效率,为单电池锂离子电池供电的便携......
  • 快速掌握AI测试开发技能,获得更好的职业机会和晋升空间
    随着人工智能在各行各业的广泛应用,学习并掌握AI技术在软件测试中的应用变得至关重要。不仅能使你跟上行业的发展趋势,还能提升你的竞争力。而且,市场对具备AI测试技能的测试工程师的需求正日益增长,这使得掌握这些技能能够帮助你获得更好的职业机会和升职机会。在测试工作中,通过应用......
  • docsify快速部署搭建个人知识库
    1.docsify介绍与文档1.1基本介绍Docsify即时生成您的文档网站。与GitBook不同,它不会生成静态html文件。相反,它会智能地加载和解析您的Markdown文件,并将它们显示为网站。没有静态构建的html文件简单轻便智能全文搜索插件多个主题有用的插件接口表情符号支持与......