快速乘 快速冪 矩陣快速冪
阿新 • • 發佈:2019-02-10
求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; }