快速幂、矩阵快速幂

快速幂、矩阵快速幂

快速幂

所谓快速幂,就是用来快速求取 a n a^n an的算法,当 n n n不大时,或者需要求取的次数不多时,我们可以直接进行 n n n次遍历求取即可,当 n n n的很大或者需要多次求取时,我们有一种更为快速的算法来求解,有多快?— O ( l o g n ) O(log n) O(logn)
我们考虑 a n ,分解 n ,即将 n 转化为二进制形式,假设 n = 27 则, a 27 = a ( 11011 ) 2 进制 = a ( 10000 ) 2 ∗ a ( 1000 ) 2 ∗ a ( 10 ) 2 ∗ a ( 1 ) 2 = a 16 ∗ a 8 ∗ a 2 ∗ a 1 = a 27 . . . . . . . ( 对 n 进行二进制分解 ) 我们考虑a^n,分解n,即将n转化为二进制形式,假设n=27\\ 则,a^{27}=a^{(11011)_{2进制}}=a^{(10000)_2}*a^{(1000)_2}*a^{(10)_2}*a^{(1)_2}\\ =a^{16}*a^{8}*a^2*a^1=a^{27}.......(对n进行二进制分解) 我们考虑an,分解n,即将n转化为二进制形式,假设n=27则,a27=a(11011)2进制=a(10000)2a(1000)2a(10)2a(1)2=a16a8a2a1=a27.......(n进行二进制分解)
那么我们根据上面的分解步骤就可以的到,
当前n的二进制位值第x为1时,只需要乘上 a 2 x a^{2^x} a2x即可,并且每次a*a,就能得到下一个位置x+1的 a 2 x + 1 a^{2^{x+1}} a2x+1
我们直接来看代码
例题:acwing875. 快速幂
代码如下:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
int ks(int a,int b,int p){
    int res=1;
    while(b){
        if(b&1) res=(ll)res*a%p;
        a=(ll)a*a%p;
        b>>=1;
    }
    return res%p;
}
int main(){
    int t,a,b,p;;
    cin>>t;
    while(t--){
        scanf("%d%d%d",&a,&b,&p);
        printf("%d\n",ks(a,b,p));
    }
    return 0;
}

矩阵快速幂

矩阵快速幂=快速幂+矩阵乘法

首先,我们先了解一下矩阵乘法的规则:
在这里插入图片描述
矩阵 A 要想与矩阵 B 相乘,那么矩阵 A 的列数就得等于矩阵 B 的行数 即, C a × b = A a × p × B p × b 所得新矩阵 C 的行数等于矩阵 A 的行数,列数等于矩阵 B 的列数 矩阵A要想与矩阵B相乘,那么矩阵A的列数就得等于矩阵B的行数\\ 即,C_{a\times b}=A_{a\times p}\times B_{p\times b}\\ 所得新矩阵C的行数等于矩阵A的行数,列数等于矩阵B的列数 矩阵A要想与矩阵B相乘,那么矩阵A的列数就得等于矩阵B的行数即,Ca×b=Aa×p×Bp×b所得新矩阵C的行数等于矩阵A的行数,列数等于矩阵B的列数
由斐波那契数列来来引出矩阵快速幂
f [ n ] = { f [ n − 1 ] + f [ n − 2 ] , n > 1 f [ 1 ] = 1 f [ 0 ] = 0 可以写成 [ f [ n ] 0 f [ n − 1 ] 0 ] = [ 1 1 1 0 ] × [ f [ n − 1 ] 0 f [ n − 2 ] 0 ] = [ 1 1 1 0 ] 2 × [ f [ n − 2 ] 0 f [ n − 3 ] 0 ] 依次类推可得: [ f [ n ] 0 f [ n − 1 ] 0 ] = [ 1 1 1 0 ] n − 1 × [ f [ 1 ] 0 f [ 0 ] 0 ] f[n]= \begin{cases} f[n-1]+f[n-2],n>1 \\f[1]=1 \\f[0]=0 \end{cases}\\ 可以写成\begin{bmatrix} f[n] & 0 \\ f[n-1] & 0 \end{bmatrix}=\begin{bmatrix} 1 & 1 \\ 1 & 0 \end{bmatrix}\times\begin{bmatrix} f[n-1] & 0 \\ f[n-2] & 0 \end{bmatrix}=\begin{bmatrix} 1 & 1 \\ 1 & 0 \end{bmatrix}^2\times\begin{bmatrix} f[n-2] & 0 \\ f[n-3] & 0 \end{bmatrix}\\依次类推可得:\\ \begin{bmatrix} f[n] & 0 \\ f[n-1] & 0 \end{bmatrix}=\begin{bmatrix} 1 & 1 \\ 1 & 0 \end{bmatrix}^{n-1}\times\begin{bmatrix} f[1] & 0 \\ f[0] & 0 \end{bmatrix} f[n]= f[n1]+f[n2],n>1f[1]=1f[0]=0可以写成[f[n]f[n1]00]=[1110]×[f[n1]f[n2]00]=[1110]2×[f[n2]f[n3]00]依次类推可得:[f[n]f[n1]00]=[1110]n1×[f[1]f[0]00]
也就是说,我们只需要算出 [ 1 1 1 0 ] n − 1 \begin{bmatrix} 1 & 1 \\ 1 & 0 \end{bmatrix}^{n-1} [1110]n1即可求出 [ f [ n ] 0 f [ n − 1 ] 0 ] \begin{bmatrix} f[n] & 0 \\ f[n-1] & 0 \end{bmatrix} [f[n]f[n1]00],而 [ 1 1 1 0 ] n − 1 \begin{bmatrix} 1 & 1 \\ 1 & 0 \end{bmatrix}^{n-1} [1110]n1我们可以用快速幂的思想在 O ( l o g n ) O(log n) O(logn)的时间复杂度内求出。
例题:acwing205. 斐波那契
代码如下:

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long ll;
const int P=10000; 

struct node{
    int data[5][5];
};
node mul(node a,node b){//矩阵乘法
    node res;
    memset(res.data,0,sizeof res.data);
    for(int i=1;i<=2;i++)
        for(int j=1;j<=2;j++)
            for(int k=1;k<=2;k++)
                res.data[i][j]=(res.data[i][j]+(ll)a.data[i][k]*b.data[k][j]%P)%P;
    return res;
}

node ks(node a,int b){//快速幂
    node res;
    memset(res.data,0,sizeof res.data);
    for(int i=1;i<=2;i++) res.data[i][i]=1;
    while(b){
        if(b&1) res=mul(res,a);
        b>>=1;
        a=mul(a,a);
    }
    return res;
}

int main(){
    int n;
    while(scanf("%d",&n)&&n!=-1){
        if(!n){
            printf("0\n");
            continue;
        }
        node f,base;
        f.data[1][1]=1;f.data[1][2]=0;//初始斐波那契数列
        f.data[2][1]=0;f.data[2][2]=0;
        
        base.data[1][1]=1;base.data[1][2]=1;//构建矩阵
        base.data[2][1]=1;base.data[2][2]=0;
        
        node ant=ks(base,n-1);
        
        node res=mul(ant,f);
        
        cout<<res.data[1][1]<<endl;
        
    }
    return 0;
}

斐波那契数列差不多是最简单的矩阵快速幂的应用,矩阵快速幂的难点在于如何构建一个矩阵,使其能够满足递推式。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

chp的博客

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值