zoukankan      html  css  js  c++  java
  • 快速乘,快速幂和矩阵快速幂

    快速乘

    引用:https://blog.csdn.net/kahcc/article/details/89334674
    我们可以把b拆为一个二进制数。
    首先我们可以将指数b转换为一个二进制数。
    例如b=9,对应的二进制数为1001。那么我们可以得到(9=1*2^3+0*2^2+0*2^1+1*2^0)
    那么便可以得出性质1:(a*9=a*(2^3+2^0))
    根据这个性质我们便可以做快速乘了。
    对于快速乘来说。
    我们用ans记录当前的答案,用b&1判断当前位为1,还是为0。
    根据性质1我们可以知道,如果当前我们推到的二进制数的位数上是1(例如9转换为二进制数后的第0位和第3位),那么(ans = ans + a * 2),否则ans不用更新。
    而无论ans是否更新,a和b都需要继续判断下一步(即需要更新)。
    其中,b需要判断高一位是否为1(即右移一位),a需要往前进一位(即左移一位,(2^0->2^1)

    public static int qmul_num(int a, int b) {
        int ans = 0;
        while (b != 0) {
            if ((b & 1) != 0) {
                ans += a;
            }
            b >>= 1;
            a <<= 1;
        }
        return ans;
    }
    

    如果是快速模乘的话,多一步取模:

    public static int qmul_mod(int a, int b, int mod) {
        int ans = 0;
        while (b != 0) {
            if (((b %= mod) & 1) != 0) {
                ans += a %= mod;
            }
            b >>= 1;
            a <<= 1;
        }
        return ans % mod;
    }
    

    快速幂

    引用:https://blog.csdn.net/Harington/article/details/87602682

    (a^b%m) 的值,这个用普通算法我就不说了,时间复杂度O(b)。神奇的快速幂,时间复杂度O(logb).
    我们已知 (2^3)(2^6),不就是 (2^3 * 2^3)嘛。快速幂就是这个原理。
    那有同学问了遇到奇数怎么办?(2 ^ 5)??
    那不就是 (2 * 2 ^ 4) 这不就成了嘛。
    所以这就是快速幂的基本思路求(a ^ b).
    原理:

    1)当b是奇数时,那么有 (a^b = a * a^{(b-1)})
    2)当b是偶数时,那么有 (a^b = a^{(b/2)} * a^{(b/2)})

    举个例子?

    2 ^10 =
    2^10 = 2^5 * 2^5
    2^5 = 2 * 2^4
    2^4 = 2^2 * 2^2
    2^2 = 2^1 * 2^1
    2^1 = 2 * 2^0

    根据这两个条件写递归式:

    typedef long long ll;
        ll binaryPow(ll a, ll b, ll m) {
            ll temp;
            if (b == 0)
                return 1;
            else if (b % 2 == 1)
                temp = a * binaryPow(a, b - 1, m) % m;
            else {
                temp = binaryPow(a, b / 2, m) % m;
                temp = temp * temp % m;
            }
            return temp;
        }
    

    其中

    b % 2 == 1
    可换成
    b & 1
    

    此为按位与,判断b的末尾是否为1 ,因此当b 为奇数时 b & 1 返回为1,if条件成立,这样执行速度更快。

    +-一般使用2个CPU时钟,位运算 只要1个,* 要4个,/ 要40个

    针对不同的题目,有两个细节需要注意
    1)如果初始值a 大于 m ,那么需要在进入函数前就让a 对 m 取模,
    2)若果m 为 1,可以直接在函数外部特判为 0,不需要进入函数来计算。(因为任何数对1 取模都是0)。

    快速幂的迭代写法

    对于 (a ^ b)来说,若果把 b 写成2 进制,那么b 就可以写成若干二次幂之和,如13 的二进制 1101,于是3 号位 、2号位、0号位就都是1,那么就可以得到(13 = 2^3 + 2^2 + 2^1 = 8 + 4 + 1)。所以(a ^{13} = a^8 * a^4 * a^1)
    通过同样的推导,我们可以把任意的(a^b) 表示成 (a^{(2^k)}……、a^8、a^4、a^2、a^1)中若干的乘积。若果二进制的i号位为1.那么想中的(a^{(2^i)})就被选中。于是可以得到计算(a^b)的大致思路:令i 从0到k枚举b的二进制的每一位,如果为1 那就累计(a^{(2^i)})。注意 (a^{(2^k)}……、a^8、a^4、a^2、a^1)前一项总是等于后一项的平方。
    具体步骤:
    (1)初始令ans = 1,用来存放累积的结果。
    (2)判断b的二进制末尾是否为1 ,(及判断 b&1 是否为 1),也可以理解为判断b是否为奇数。如果是的话,令ans乘上a的值。
    (3)令a平方,并使b右移一位,(也可以理解为,b/2)
    (4)只要b大于0,就返回(2)。
    代码:

        ll binaryPow(ll a, ll b, ll m) {
            ll ans = 1;
            while (b > 0) {
                if (b & 1) {
                    ans = ans * a % m;
                }
                a = a * a % m;
                b = b >> 1;
            }
            return ans;
        }
    

    矩阵快速幂

    类似于快速幂方法。

    引用:https://blog.csdn.net/red_red_red/article/details/90208713

    //定义矩阵 
    struct node {
    	int mat[15][15];
    }x,y;
    //矩阵乘法
    node mul(node x,node y){
    	node tmp;
    	for(int i=0;i<len;i++){
    		for(int j=0;j<len;j++){
    			tmp.mat [i][j]=0;
    			for(int k=0;k<len;k++){
    				tmp.mat [i][j]+=(x.mat [i][k]*y.mat [k][j])%mod;
    			}
    			tmp.mat [i][j]=tmp.mat[i][j]%mod;
    		}
    	}
    	return tmp;
    //矩阵快速幂
    node matpow(node x,node y,int num){
    	while(num){
    		if(num&1){
    			y=mul(y,x);
    		}
    		x=mul(x,x);
    		num=num>>1;
    	}
    	return y;
    }
    
  • 相关阅读:
    Evolution of Image Classifiers,进化算法在神经网络结构搜索的首次尝试 | ICML 2017
    YOLOv1/v2/v3简述 | 目标检测
    MetaQNN : 与Google同场竞技,MIT提出基于Q-Learning的神经网络搜索 | ICLR 2017
    FCOS : 找到诀窍了,anchor-free的one-stage目标检测算法也可以很准 | ICCV 2019
    canvas图表(3)
    WebGL学习(2)
    canvas图表(1)
    WebGL学习(1)
    前端特效列表
    canvas绘制太阳系
  • 原文地址:https://www.cnblogs.com/xym4869/p/12240806.html
Copyright © 2011-2022 走看看