快速幂,矩阵快速幂

快速幂:复杂度为logn,比普通的n快了很多了.

原理 :

以求a的b次方来介绍:
首先把b转换成二进制数
该二进制数第i位的权为  2^i - 1 .
比如 : 11的二进制是1011
11 = 2³×1 + 2²×0 + 2¹×1 + 2º×1

所以假设我们要求a^b,那么其实b是可以拆成二进制的,该二进制数第i位的权为2^(i-1),例如当b==11时
           a^11=a^(2^0+2^1+2^3)

实现代码如下:(位运算,简单,简洁)

long long pow(int a,int b)  //位运算
{
    long long r=1,base=a;
    while(b)
    {
        if(b&1)  r*=base;   //r才是最终我们要的结果.
        base *= base ;     //一个中间转移量.b每右移一次,base就多一个平方.
        b >>= 1 ;
    }
    return r;
}

矩阵快速幂:

思想和快速幂差不多,只是这里是矩阵 , 而那个是数的差别.

所以原理和思想就不多说了 , 然后直接上代码

while(b)
{
    if(b&1) res *= A;   //res是结果矩阵.
    
    A *= A;           //和快速幂一样,每一次都是乘一个平方,因为最多也是差2的几次方的问题.
    b >>= 1 ;
}

难点在于如何构造A矩阵,只要构造出来了就简单了.
给一道好题:点这(自己通过看下面那篇博客,自己推推,尽量不要搜题解)
不知道怎么建矩阵的请看这里,这个讲的超级好点这里, 点这里, 看见了吗, 点这里啊
思路就是很简单:就是矩阵快速幂,主要是建好矩阵.

提供一个骚气的写法,就可以不用每一次写矩阵形式,就是重载 * 号运算符. 代码如下:

#define ll long long
#define db double
#define CLR(x) memset(x,0,sizeof(x))
const int ssize=10;
struct Ma{
    db a[30][30];
    void cc(){
        CLR(a);
    }
    Ma operator * (const Ma &b) const {      //重载 * 号运算符.
        Ma tmp;
        tmp.cc();
        for(int i=0;i

(怎么推要求那个矩阵的几次方,就是用等比数列,an = a(n-1) * q ,然后看题目给的那一项从而推出是q的几次方.)

好题的AC代码:

#include
#include
#include
#include
#include
#define ll long long
using namespace std;
const ll mod = 2147493647;

struct Ma
{
    ll a[10][10];

    void cc()
    {
        memset(a,0,sizeof(a));
    }
    Ma operator * (const Ma & b) const {
        Ma tmp;
        tmp.cc();
        for(int i=0;i<7;i++){
            for(int j=0;j<7;j++){
                for(int k=0;k<7;k++){
                    tmp.a[i][j] += (a[i][k] * b.a[k][j]);
                    tmp.a[i][j] %= mod;
                }
            }
        }
        return tmp;
    }
}res,x;


void init()
{
    res.cc();
    for(int i=0;i<7;i++)    //初始化为单位矩阵.
        res.a[i][i] = 1 ;


    x.cc();    // 初始化所推的那个矩阵.
    x.a[0][0] = x.a[0][1] = 1;
    x.a[1][0] = 2;
    x.a[2][0] = x.a[2][2] = 1;
    x.a[3][2] = 4 , x.a[3][3]=1;
    x.a[4][2] = 6 , x.a[4][3] = 3 ,x.a[4][4] = 1 ;
    x.a[5][2] = 4 , x.a[5][3] = 3 , x.a[5][4] = 2 , x.a[5][5] = 1 ;
    x.a[6][2] = x.a[6][3] = x.a[6][4] = x.a[6][5] = x.a[6][6] = 1;

}

void qpow(ll n)
{

    while(n)
    {
        if(n&1) res = res * x;
        x = x*x ;
        n >>= 1;
    }
}


int main()
{
    int t;
    cin >> t;
    while(t--){
        ll N,m,n;
        init();
        cin >> N >> m >> n;
        if(N < 3){
            if(N == 1)
                cout << m << endl;
            else
                cout << n << endl;
            continue;
        }
        ll s[10] = {n,m,81,27,9,3,1};   //相当于第2项那个.这个就要自己想了.
        qpow(N-2);
        ll ans = 0 ;
        for(int i=0;i<7;i++){
            ans += ( res.a[i][0] * s[i] );
            ans %= mod;
        }
        cout << ans << endl;
    }
}

还有一道跟这道好题很相似的题(也是也一道好题!)链接在此

觉得没过瘾,就再来做一道题,这道题不是这么容易看出来用矩阵快速幂来做哈,(这里都已经提醒你了,xixi)链接在此

你可能感兴趣的:(快速幂,矩阵快速幂)