【蓝桥杯】矩阵快速幂

一.快速幂概述

1.引例

1)题目描述:

求A^B的最后三位数表示的整数,A^B表示:A的B次方。

2)思路: 

一般的思路是:求出A的B次幂,再取结果的最后三位数。但是由于计算机能够表示的数字的范围是有限的,所以会产生“指数爆炸”的现象(即发生溢出现象)。

换一种思路来看本题:

取模运算的公式如下:

(a+b)\%p=a\%p+b\%p\\ (a-b)\%p=a\%p-b\%p\\ (a\times b)\%p=(a\%p\times b\%p)\%p

结论:

多个因子连续的乘积取模的结果等于每个因子取模后的乘积再取模的结果。

我们可以借助这个法则,只需要在循环乘积的每一步都提前进行“取模”运算,而不是等到最后直接对结果“取模”,也能达到同样的效果。

3)代码如下:

long long normalPower(long long a,long long b){
    long long result=1;
    for(int i=0;i<b;i++){
        result=(result*(a%1000))%1000;
    }
    return result%1000;
}

 

 2.快速幂算法

1)思路:

快速幂算法能够帮我们算出指数非常大的幂。

传统算法时间复杂度高的原因是:指数很大,循环次数多。

核心思想:每一步都将指数分成两半,而相应的底数做平方运算。

2)代码:

//获取最后三位数
long long fastPower(long long base,long long power){
    long long re=1;
    while(power>0){
        if(power%2){//指数为奇数
            power--;//指数-1,将其变为偶数
            re=re*base%1000;
        }
        power/=2;
        base=base*base%1000;
    }
    return re;
}

 通过位运算进行优化:

long long FastPower(long long base,long long power){
    long long re=1;
    while(power>0){
        if(power&1){
            re=re*base%1000;
        }
        power=power>>1;
        base=(base*base)%1000;
    }
    return re;
}

二.矩阵快速幂

矩阵乘法:

for(i=1;i<=n;i++)
{
    for(j=1;j<=n;j++)
    {
        for(k=1;k<=n;k++)
        {
            c[i][j] += a[i][k] * b[k][j];
        }
    }
}

 矩阵快速幂:

仿照大数的快速幂

//矩阵快速幂
#include<iostream>
#include<cstring>
using namespace std;


int M,n;

struct node{
    int m[100][100];
}ans,res;//ans是结果,res为最初的方阵

struct node mul(struct node A,struct node B){
    struct node C;
    int i,j,k;
    
    for(i=0;i<n;i++)
        for(j=0;j<n;j++)
            C.m[i][j]=0;
    
    for(i=0;i<n;i++){
        for(j=0;j<n;j++){
            for(k=0;k<n;k++){
                C.m[i][j]+=A.m[i][k]*B.m[k][j];
            }
        }
    }
    return C;
}

void quickpower(){
    int i,j;
    //初始ans为单位矩阵
    for(i=0;i<n;i++)
        for(j=0;j<n;j++)
            if(i==j)
                ans.m[i][j]=1;
            else
                ans.m[i][j]=0;
    while(M>0){
        if(M&1){
            ans=mul(ans,res);
        }
        res=mul(res,res);
        M=M>>1;
    }
}
int main(){
    cin>>n;
    cin>>M;
    for(int i=0;i<n;i++)
        for(int j=0;j<n;j++)
            cin>>res.m[i][j];
    quickpower();
    for(int i=0;i<n;i++){
        for(int j=0;j<n;j++)
            cout<<ans.m[i][j]<<' ';
        cout<<endl;
    }
    return 0;
}

三.实战演练

1.题目描述:

2.问题分析: 

 转换为矩阵相乘的形式。

3.代码实现:

//斐波那契数列
#include<iostream>

using namespace std;

const int N=1e4;
const long long mod=1e9+7;
int T;
long long a[N];

struct node{
    long long m[2][2];
}ans,res;

//矩阵乘法
struct node mul(struct node a,struct node b){
    struct node c;
    c.m[0][0]=(a.m[0][0]*b.m[0][0]+a.m[0][1]*b.m[1][0])%mod;
    c.m[0][1]=(a.m[0][0]*b.m[0][1]+a.m[0][1]*b.m[1][1])%mod;
    c.m[1][0]=(a.m[1][0]*b.m[0][0]+a.m[1][1]*b.m[1][0])%mod;
    c.m[1][1]=(a.m[1][0]*b.m[0][1]+a.m[1][1]*b.m[1][1])%mod;
    return c;
}

//矩阵快速幂
struct node matrixPower(struct node base,long long exp){
    struct node res={1,0,0,1};
    while(exp>0){
        if(exp&1){
            res=mul(res, base);
        }
        exp=exp>>1;
        base=mul(base, base);
    }
    return res;
}

//求斐波那契数列第n项
long long f(long long n){
    struct node base={1,1,1,0};
    struct node res=matrixPower(base, n-1);
    return res.m[0][0];
}
int main(){
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    cin>>T;
    for(int i=0;i<T;i++){
        cin>>a[i];
    }
    for(int i=0;i<T;i++){
        cout<<f(a[i])<<'\n';
    }
    return 0;
}

相关推荐

  1. 每日一题:转圈游戏(快速

    2024-03-31 16:02:05       17 阅读
  2. 每日一题(快速、组合计数)

    2024-03-31 16:02:05       16 阅读

最近更新

  1. TCP协议是安全的吗?

    2024-03-31 16:02:05       18 阅读
  2. 阿里云服务器执行yum,一直下载docker-ce-stable失败

    2024-03-31 16:02:05       19 阅读
  3. 【Python教程】压缩PDF文件大小

    2024-03-31 16:02:05       18 阅读
  4. 通过文章id递归查询所有评论(xml)

    2024-03-31 16:02:05       20 阅读

热门阅读

  1. 洛谷P1000超级玛丽游戏C++

    2024-03-31 16:02:05       13 阅读
  2. Stable Diffusion 推荐硬件配置和本地化布署

    2024-03-31 16:02:05       18 阅读
  3. 【shell】shell实现等待用户输入

    2024-03-31 16:02:05       12 阅读
  4. 【华为OD机试C++】进制转换

    2024-03-31 16:02:05       14 阅读
  5. [单调队列] 滑动窗口

    2024-03-31 16:02:05       13 阅读
  6. 一文总结vue和react的区别

    2024-03-31 16:02:05       14 阅读
  7. zookeeper命令详解1

    2024-03-31 16:02:05       18 阅读
  8. Zookeeper中的ACL 权限控制机制

    2024-03-31 16:02:05       13 阅读
  9. 初识 内嵌iframe

    2024-03-31 16:02:05       14 阅读