算法学习 - 快速幂和矩阵快速幂(复杂度Olog(n))C++实现

快速幂

快速幂顾名思义,就是快速算某个数的多少次幂。其时间复杂度为 O(log?N), 与朴素的O(N)相比效率有了极大的提高。

快速幂实现原理

快速幂的原理比较好懂,就是说假如我们求的是3^11,其实比较通用的办法就是

for 1:11

a*=3;

时间复杂度为O(n), 那么我们有没有更快的办法呢? 有的~就是下面要说的快速幂。

快速幂就是把指数进行一次log(N)级别的变换。11 = 2^3+2^1+2^0

那么我只需要算3^13^2还有3^8这样复杂度就降下来了。算3^1需要一次记为a,把a平方就是3^2记为b,把b平方就是3^4记为c,再平方就是3^8记为d,这样把a
b d
乘以之后就是结果了。这样速度就快起来了~

快速幂代码

代码如下:

这个代码因为比较简单,所以很容易懂,下面的矩阵快速幂是我自己写的,可能会比较难~

int pow3(int a,int b)
{
    int ans = 1,base = a;
    while(b!=0)
    {
        if(b&1)
            ans *= base;
        base *= base;
        b>>=1;
    }
    return ans;
}

矩阵快速幂

矩阵快速幂是个很好玩的东西~ 为啥捏? 因为它能在Olog(N)级别的时间求的第N个斐波纳挈数列~叼不叼~(什么?你不知道什么是斐波纳挈。请百度~1 1 2 3 5 8...数列)

实现原理

那是怎么实现呢?首先我们设立ans矩阵{1, 1; 1, 0}.然后这个矩阵就是类似上面的3这个底数,然后直接矩阵相乘就可以了。

斐波纳挈数列是F(n) = F(n-1) + F(n-2),下面的代码是难一点的,F(n)
= a*F(n-1) + b*F(n-2)
这个数列的,F(1) = F(2) = 1.

实现代码

代码如下:

//
//  main.cpp
//  numberSequence_hdu
//
//  Created by Alps on 14/12/22.
//  Copyright (c) 2014年 chen. All rights reserved.
//

#include <iostream>
using namespace std;

void multiMatrix(int ma[][2],int a, int b){
    int i,j;
    int cp[2][2] = {0,0,0,0};;
    for (i = 0; i < 2; i++) {
        for (j = 0; j < 2; j++) {
            cp[i][j] = ((ma[i][0]*ma[0][j])%7 + (ma[i][1]*ma[1][j])%7)%7;
//            printf("%d ",cp[i][j]);
        }
//        printf("\n");
    }
    for (i = 0; i < 2; i++) {
        for (j = 0; j < 2; j++) {
            ma[i][j] = cp[i][j];
        }
    }
}

void multiDoubleMatrix(int cp[][2], int ma[][2], int a, int b){
    int temp[2][2];
    int i,j;
    for (i = 0; i < 2; i++) {
        for (j = 0; j < 2; j++) {
            temp[i][j] = ((cp[i][0]*ma[0][j])%7 + (cp[i][1]*ma[1][j])%7)%7;
        }
    }
    for (i = 0; i < 2; i++) {
        for (j = 0; j < 2; j++) {
            cp[i][j] = temp[i][j];
        }
    }
}

int calculate(int ma[][2], int a, int b, int c){
    if (c <= 0) {
        return 1;
    }
    int cp[2][2] = {1,0,0,1};
    while (c) {
        if (c&1) {
            multiDoubleMatrix(cp, ma, a, b);
        }
        multiMatrix(ma, a, b);
        c = c>>1;
    }
    return (cp[0][0]+cp[0][1])%7;
}

int main(int argc, const char * argv[]) {
    int a,b,c;
    while (1) {
        scanf("%d %d %d",&a,&b,&c);
        int ma[][2] = {a%7,b%7,1,0};
//        printf("%d %d %d %d\n",ma[0][0],ma[0][1],ma[1][0],ma[1][1]);
        if (a == 0 && b == 0 && c == 0) {
            break;
        }
        printf("%d\n",calculate(ma, a, b, c-2));
    }

    return 0;
}
时间: 2024-10-29 19:06:12

算法学习 - 快速幂和矩阵快速幂(复杂度Olog(n))C++实现的相关文章

算法初步:快速乘,快速幂,矩阵快速幂

原创 by zoe.zhang 在刷题的时候遇到了问题,就是当循环或者递推的次数非常大的情况下获取一定结果,这个时候如果作普通运算,那么很容易就超时了,而且有时候结果也大得超范围了,即使是long long类型的也放不下,然后给了提示说是运用快速幂的思想.所以这里对快速幂做了一点思考和探讨. 1.快速乘,快速幂,矩阵快速幂三者的关系 不管是快速乘,还是快速幂算法,实际上都包含了分解问题的思想在里面,将O(n)的复杂度降到O(lgn).学习的时候,一般学习快速幂算法,再由此推广去解决矩阵快速幂问题

快速乘、快速幂(矩阵快速幂)

当mod一个大数p的时候,还有进行乘法的时候可能会爆long long的时候,就用快速乘或者快速幂. 参考:http://www.cnblogs.com/whywhy/p/5066730.html 先上模板: 快速乘: ll multi(ll a,ll b,ll m) { ll ans=0; while(b) { if(b&1) (ans+=a) %= m; (a=a*2) %= m; b/=2; } return ans; } 快速幂: ll pow_mod(ll a,ll b,ll m) {

算法录 之 快速幂快速乘和矩阵快速幂。

1: 问题如下: 求 a^n % m 的值是多少?n是1到10^18次方的一个整数. 求一个数的n次方,朴素的算法就是直接for循环,O(N)的复杂度. 但是对于这个问题n实在是太大了,O(N)也会超时,那么需要更快的算法,快速幂算法. 要求 a^n,如果知道了 a^(n/2) 次方的话,再来个平方就可以了. 那么按照这个思路就能运用分治的思想了. 代码如下: 1 int _pow(int a,long long n,int m) { 2 if(n==0) return 1 % m; 3 4 l

快速幂与矩阵快速幂

快速幂的思路: 仍然是与2 分法有关的算法:(很多O(logN)的算法都是二分法啊...) 但快速幂有个前题,就是数据类型必须满足结合律 对于一般的解法: A^8 = A * A * A * A * A * A * A * A 总共需要7次乘法运算: 将其平均分解: A^8 = (A * A * A * A) * (A * A * A * A) = (A * A * A * A) ^ 2 这样我们就只需要4次乘法运算了: 我们还可以将其再分解: A^6 = [(A * A) * (A * A)]

快速幂和矩阵快速幂模板

快速幂模板: ll qmod(ll x,ll n,ll mod) { ll res=1; while(n){ if(n&1) res=(res*x)%mod; x=(x*x)%mod; n/=2; } return res; } 例题:hdu 1097 #include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #include<cmath> usin

二进制快速幂及矩阵快速幂

二进制快速幂 二进制快速幂虽然不难写,但是无奈总是会忘,所以还是在这里把板子写一下. 二进制快速幂很好理解: 假设我们要求a^b,那么其实b是可以拆成二进制的,该二进制数第i位的权为2^(i-1),例如当b==11时,11的二进制是1011,11 = 23×1 + 22×0 + 21×1 + 2o×1,因此,我们将a11转化为算 a2^0*a2^1*a2^3 int poww(int a, int b) { int ans = 1, base = a; while (b != 0) { if (

关于快速幂、快速乘、矩阵快速幂

一.快速幂 快速幂是用于解决类似$a^b$ $mod$ $p$值类型的问题的.使用普通的方法是从$1$循环至$b$,再逐次累乘,逐次取模.但这种方法对于$b$很大的时候却可能会超时.那么,这时候我们就需要使用快速幂了. 快速幂是基于以下式子: 若$b$ $mod$ $2=1$,则$a^b=a^\frac{b}{2}\times a^\frac{b}{2}\times a$ 若$b$ $mod$ $2=0$,则$a^b=a^\frac{b}{2}\times a^\frac{b}{2}$ 这样,我

快速幂和矩阵快速幂-模板

快速幂的思想就是减少相乘的次数,将原本n-1次的相乘减小到(lg(n))的复杂度: a^b=(a^2)^(b/2) 这个式子由于/是整除,所以得分奇偶的不同情况,偶数时仍然成立,奇数时需要再乘上一个a: 所以快速幂就是将原本的以a为基本单位的连乘改成以a*a为单位的连乘: 代码: 1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 using namespace std; 5 int quick

算法总结之 将正方形矩阵顺时针转动90度

给定一个 N * N的矩阵,把这个矩阵调整成顺时针转动90度后的形式 要求额外空间复杂度为O(1) 这里仍然使用分圈处理方式 如果你愿意一层一层一层的拨开我的心~  哈哈哈 由外到内的旋转 上代码一目了然: