zoukankan      html  css  js  c++  java
  • 快速幂

    快速幂的作用:

    就是为了快速的算出(a^k(mod)p),先看朴素算法,如果算a^k那么得用一个for循环,效率为(O(n)),但是如果使用快速幂那么效率就成变成了(O(logn)),所以说效率还是很高的。

    原理:

    因为k有([log_2k] + 1)个二进制位,所以我们需要预处理出(a^{2^0}(mod)p), (a^{2^1}(mod)p),.....(a^{2^{log_2k}}(mod)p),一共有(log_2k)个,因此时间复杂度是(O(logk)),然后再组合出(a^k)即可,就是将(a^k)拆成(a^{i_1}*a^{i_2}...)的形式,整理一下就是(a^{i_1 + i_2 + ....})的形式,因此我们可以分两步:

    • 第一步先处理k的二进制:假设((k)_10 = (110110)_2),那么k的二进制形式就是(2^5 + 2^4 + 2^2 + 2^1),因此二进制位上为1的加上即可
    • 第二步:快速处理出(a^{2^0}), (a^{2^1})....,很容易发现,(a^{2^1} = {(a^{2^0}})^2),即每一项是前一项的平方

    都处理完之后,就可以把(a^k)拆成(a^{i_1}*a^{i_2}...)的形式了

    感觉自己说的都一懵一懵的,举个例子:
    假设要算(4^5(mod)9),那么我们可以将(5)拆解成它的二进制形式((0101)),于是:

    [4^5(mod)9 = 4^{2^0}(mod)9 * 4^{2^2}(mod)9 = 4^{2^0 + 2^2}(mod)9 ]

    代码:

    int qmi(int a, int k, int p) {
        int res = 1;
        if(k == 0 && p == 1) return 0; //可能会出现k == 0 p == 1的情况, 需要特判
        while(k) {
            if(k & 1) res = (LL)res * a % p; //不要忘了long long很重要
            k >>= 1;
            a = (LL)a * a % p;
        }
        return res;
    }
    

    矩阵快速幂

    与普通的快速幂类似,求(A^k)(A是一个矩阵)只不过是多了一个矩阵乘法,再有就是注意一些细节了,long long的使用,直接看代码吧

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    
    using namespace std;
    
    typedef long long LL;
    const int N = 110, Mod = 1e9 + 7;
    long long n, k;
    
    void mul(LL a[][N], LL b[][N], LL c[][N]) {
        LL temp[N][N] = {0};
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                for (int k = 0; k < n; k++) {
                    temp[i][j] = (temp[i][j] + (LL)b[i][k] * c[k][j] % Mod) % Mod; //防止溢出
                }
            }
        }
        memcpy(a, temp, sizeof temp);
    }
    
    int main() {
        LL a[N][N], res[N][N];
        scanf("%lld%lld", &n, &k); //因为都是long long类型 因此用lld读入
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                scanf("%lld", &a[i][j]);
                res[i][j] = a[i][j];
            }
        }
        k--;
        while(k) {
            if(k & 1) mul(res, res, a);
            mul(a, a, a);
            k >>= 1;
        }
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                printf("%lld ", res[i][j]);
            }
            puts("");
        }
        return 0;
    }
    

    还有一些典型的例题 比如fib求值,求前n项和等等,会填坑的

  • 相关阅读:
    Django时区导致的datetime时间比较报错
    Django 插件之 Xadmin实现富文本编辑器
    xadmin自定义菜单、增加功能、富文本编辑器
    virtualenv虚拟环境搭建及pipreqs自动生成第三方模块简介
    Selenium 多窗口元素定位处理
    selenium 消息框元素定位处理
    无界面运行Jmeter压测脚本
    网站死链的扫描
    Jmeter关联处理
    逻辑思维训练
  • 原文地址:https://www.cnblogs.com/ZhengLijie/p/13798866.html
Copyright © 2011-2022 走看看