浅谈矩阵快速幂的技巧和应用

1:基础知识

(1)矩阵快速幂其实就是一个矩阵乘法,加快速幂的思想,下面简单介绍一下矩阵乘法怎么运算。
对于矩阵C=A*B
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
其中c[i][j]为A的第i行与B的第j列对应乘积的和,即:在这里插入图片描述

代码:
有二种写法,一般这种就够用了,这里只介绍这种

mat operator *(mat x,mat y) //重载乘法
{
    mat ret;
    for(int i=0;i<mx;i++)//mx可以根据题目要求具体变化
       for(int j=0;j<mx;j++)
    {
        ret.m[i][j]=0;
        for(int k=0;k<mx;k++)
            ret.m[i][j]=(x.m[i][k]*y.m[k][j]+ret.m[i][j])%mod;
    }
    return  ret;
}

下面给出通用模板,个人觉得一个很好的模板,有些模板看着看着就晕了。然后我总结了一个可以通用的模板。

#include<iostream>
#include<algorithm>
#include<map>
#include<cstring>
#include<vector>
#include<cstdio>
#include<cmath>
using namespace std;
typedef long long ll;
const ll mod=10000;
const ll mx=2;//根据题目改
struct mat{
    ll m[mx][mx];
};
mat operator *(mat x,mat y)//矩阵乘法
{
    mat ret;
    for(int i=0;i<mx;i++)
       for(int j=0;j<mx;j++)
    {
        ret.m[i][j]=0;
        for(int k=0;k<mx;k++)
            ret.m[i][j]=(x.m[i][k]*y.m[k][j]+ret.m[i][j])%mod;
    }
    return  ret;
}
mat ff(mat a,ll n)//快速幂部分
{
    mat ret;
    memset(ret.m,0,sizeof ret.m);
    for(int i=0;i<mx;i++) ret.m[i][i]=1;
    while(n)
    {
        if(n&1) ret=ret*a;
        a=a*a;
        n>>=1;
    }
    return ret;
}
int main()
{
   int t,n;
   while(cin>>n)
   {
        if(n==-1)
            break;
         else if(n==0)
        printf("0\n");
        else if(n==1)
        printf("1\n");
        else
        {
        mat a;//A1首项
        memset(a.m,0,sizeof a.m);
        a.m[0][0]=1;
        a.m[1][0]=0;
        mat b={//公比
            1, 1,
            1, 0
        };
        a=ff(b,n-1)*a;//套公式就完事了
        cout<<a.m[0][0]<<endl;
        }
   }
   return 0;
}

2: 技巧

首先我们先说下矩阵快速幂有什么作用,它可以处理一些递推式,一般而言,我们直接一步步递推是O(n)的算法,对于n很大时,就妥妥的超时,然后我们就可以通过矩阵快速幂把时间复杂度降到O(m^3*log(n)),m是矩阵的大小,n是求的第几项。

现在我先解释一下为什么它通用:

对于矩阵而言。所以矩阵都可以看作:
这个式子(大家可以自己推下,算下,T的一次方,T的二次方,在乘上A1的值,得出来的结果。具体证明我也不会 ),看成一个等比数列,A1是首项,T是公比
然后我们就求An就好了。
举个栗子
poj 3070
就拿我们最常见的Fibonacci来说(下面是重点,请大家牢记这些步骤

第一步:求递推式

(有些题是给出递推式的,有些题是要自己推的,求递推式没啥技巧,一般而言,求出前面几项,找规律。主要还是多练习,就有感觉了。)

第二步:求出公比T的矩阵

第三步:套模板
就那这题来说,我们可以根据递推式fn=fn-1+fn-2;
就很容易想到
在这里插入图片描述
T就等于 在这里插入图片描述
然后我们就直接套板子,输出就好了,代码就是模板。

下面给出一些常见的递推式:
1.f(n)=af(n-1)+bf(n-2)+c;(a,b,c是常数)
在这里插入图片描述
2.f(n)=c^n-f(n-1) ;(c是常数)
在这里插入图片描述
3.f(n)=a*f(n-1)+c^n在这里插入图片描述

3:应用

1.poj 3233
题解
我的ac代码:https://paste.ubuntu.com/p/hM6mXdFjpS/
2.hdu5015
题解
我的ac代码:https://paste.ubuntu.com/p/fP5MRqtKxg/
3hdu1757
题解
我的ac代码:https://paste.ubuntu.com/p/xHNxWmMDTy/
4.hdu3483
题解,关键还是找递推式的规律Sn=Sn-1+X
我的ac代码:https://paste.ubuntu.com/p/6JG8D2Pqj3/
5.hdu1575
题目比较简单,直接给出ac代码,矩阵的迹,主对角线上的元素之和
6.hdu2276
题解,这题思路构造矩阵
我的ac代码:
https://paste.ubuntu.com/p/Gh9rCzSKfG/
7.hdu2855
题解,结论题,也可以是规律题
我的ac代码:https://paste.ubuntu.com/p/8MzvK6y7Z9/
8.hdu4565
题解,这题算是我写了很久的题,至于推结论我也不是会,(这是一类技巧题),但知道它怎么来的了,不会的同学可以私聊我
我的ac代码:https://paste.ubuntu.com/p/PhV46jnMjY/

  • 9
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值