憨憨也能看懂的快速幂+矩阵快速幂

快速幂:

一、主要思想:

求ab时,将b化为二进制考虑,从而大幅减少时间复杂度。快速幂的时间复杂的为O(log2n)一般的幂乘运算为O(n)。
例如求412.12的二进制是1100,即12=123+122+021+020.也就是说单从12的二进制1100来看,后面两个0对结果来说是无意义的。所以我们只需在有1的位置上将结果保持就可以了,再使用>>运算符进行移位运算,累乘进行进位。
大概是这种感觉:
在这里插入图片描述

二、代码模板:

ll dpow(ll a,ll b)
{
    ll ans=1;
    while(b)
    {
        if(b&1) ans=ans*a%mod;
        a=a*a%mod;
        b>>=1;
    }
    return ans%mod;
}

快速幂还可以在运算的过程中就进行取模,这样就可以解决数据范围超过long long但对结果要求取模的问题.

三、例题:

博主的个人A题合集(仅供参考,不喜勿喷)



矩阵快速幂:

一、基本思想:

与快速幂相同,只是把求数的幂运算换成了矩阵。

二、代码模板:

struct mar
{
    ll x[2][2];
};
mar Mul(mar a,mar b,ll n)//自定义矩阵相乘运算
{
    mar c;
    memset(c.x,0,sizeof(c.x));
    for(int i=0; i<n; i++)
        for(int j=0; j<n; j++)
            for(int k=0; k<n; k++)
                c.x[i][j] = (c.x[i][j] + (a.x[i][k] * b.x[k][j]) % mod) % mod;
    return c;
}
mar quick_matrix(mar m,ll n)//矩阵快速幂
{
    mar res;
    for(int i=0; i<2; i++)//初始化一个单位矩阵,相当于数乘的1
        res.x[i][i]=1;
    res.x[1][0]=0;
    res.x[0][1]=0;
    while(n)
    {
        if(n&1)
            res=Mul(res,m,2);
        m=Mul(m,m,2);
        n>>=1;
    }
    return res;
}

三、例题

帮我求一下斐波那契数列吧

描述:
AYY小朋友对斐波那契数非常感兴趣,他知道f[1]=1,f[2]=1,并且从第三个斐波那契数开始f[n]=f[n-2]+f[n-1](n>=3),可是AYY小朋友只会计算前十个斐波那契数,因此他向你请教,让你帮忙计算第N个斐波那契数是多少,但是由于结果非常大,只需告诉他对1000000007取模的结果。
输入:
多组测试数据

每行一个n(1<=n<=2^32-1)
输出:
输出第n个斐波那契数的结果(对1000000007取模)
样例:
[input]:
1
10
100
1000
10000
[output]:
1
55
687995182
517691607
271496360
解题代码:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int mod=1000000007;
struct mar
{
    ll x[2][2];
};
mar Mul(mar a,mar b,ll n)
{
    mar c;
    memset(c.x,0,sizeof(c.x));
    for(int i=0; i<n; i++)
        for(int j=0; j<n; j++)
            for(int k=0; k<n; k++)
                c.x[i][j] = (c.x[i][j] + (a.x[i][k] * b.x[k][j]) % mod) % mod;
    return c;
}
ll quick_matrix(mar m,ll n)
{
    mar res;
    for(int i=0; i<2; i++)
        res.x[i][i]=1;
    res.x[1][0]=0;
    res.x[0][1]=0;
    while(n)
    {
        if(n&1)
            res=Mul(res,m,2);
        m=Mul(m,m,2);
        n>>=1;
    }
    /*for(int i=0; i<2; i++)
        for(int j=0; j<2; j++)
            cout<<res.x[i][j]<<" ";*/
    ll ans=(res.x[0][0]+res.x[1][0])%mod;
    return ans;
}
int main()
{
    ll n;
    while(cin>>n)
    {
        mar p;
        if(n>2)
        {
            for(int i=0; i<2; i++)
                for(int j=0; j<2; j++)
                    p.x[i][j]=1;
            p.x[1][1]= {0};
            cout<<quick_matrix(p,n-2)<<endl;
        }
        else
            cout<<1<<endl;
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值