快速乘 快速幂 矩阵快速幂

来源:互联网 发布:阿里云nodejs环境部署 编辑:程序博客网 时间:2024/04/30 00:27

求pow(a, exp)% mod 的值,快速幂其实也是利用了倍增的思想在里面,比如求2^12 = 2^6 * 2^6 = 2^3 * 2^3 * 2^3 * 2^3 = 2 * 2^2 * 2 * 2^2 * 2 * 2^2 * 2 * 2^2 = 2 * 2 * 2 

* 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2 * 2;即求2^12 可以用2^6 * 2^6 再进一步用之前求得的,这里只要区分指数为奇数和偶数区别对待即可。

        

typedef unsigned long long ll;const ll mod = 100000000007;ll quick_pow(ll a, ll exp, ll mod)  //mod比较大,用int或者long long下面的相乘会溢出{        ll ans = 1;        a %= mod;        while(exp)        {                if(exp & 1)         //指数为奇数                {                        ans = ((ans % mod) * (a % mod)) % mod;                        exp--;                }                exp >>= 1;                a = ((a % mod) * (a % mod)) % mod;        }        return ans;}

矩阵快速幂和上述快速幂其实是一个原理,只不过这里我们定义一个矩阵的结构体,方便操作:


const int MOD = 1e9+7;const int MAXN=105;typedef long long ll;int n;struct Matrix{    ll mat[MAXN][MAXN];    friend Matrix operator*(Matrix &m1, Matrix &m2) {        Matrix pro;        for(int i = 0; i < n; ++i) {            for(int j = 0; j < n; ++j) {                ll tmp = 0;                for(int k = 0; k < n; ++k) {                    tmp = (tmp + m1.mat[i][k]*m2.mat[k][j] % MOD) % MOD;                }                pro.mat[i][j] = tmp;            }        }        return pro;    }};Matrix quickPow(Matrix m, int p){    Matrix ans;    for(int i = 0; i < n; ++i) {        for(int j = 0; j < n; ++j) {            ans.mat[i][j] = 0;        }        // ans.mat[i][i] = 1;  无向图关系矩阵M可通过 M^k 求 u 到 v 路径长度为k总方案数 (M^k).mat[u][v]    }    while(p) {        if(p & 1) ans = ans*m;        m = m*m;        p >>= 1;    }    return ans;}

快速乘:a * k  相当于 k个a相加,处理过程和快速幂异曲同工,只是比如求 (a*b) % p时,a*b可能很大,用快速乘可以在“相乘”的过程中取模而不影响结果,防止溢出。

需要注意的是,k必须为非负整数;

typedef long long ll;ll quickMul(ll a, ll k, ll m) {    // a * k 相当于k个a相加   1 2 4 ....    ll ret = 0;    while(k){        if(k & 1) ret = (ret + a) % m;        k >>= 1;        a = (a << 1) % m;    }    return ret;}


1 0