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