快速乘 快速幂 矩阵快速幂

求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;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值