普通快速幂
思想
\(a ^ b = a\) 的所有 \(b\) 的二进制位为 \(1\) 的位在十进制下表示的数的次方。
例子
如 \(3 ^ {11}\)。
首先 \(11\) 在二进制下的表示为 \((1011)_2\), 依次表示 \(8, 2, 1\)。
且 \(3 ^ {11}\) = \(3^8 \times 3 ^ 2 \times 3 ^1\)。
所以我们发现,\(a ^ b = a\) 的所有 \(b\) 的二进制位为 \(1\) 的位在十进制下表示的数的次方。
于是我们发现如果 \(b\) 的(当前)第一个二进制位为一,则将答案乘上这位表示的数,并将 \(b\) 右移一位,即抛掉这刚刚乘出来的数,并重复这一过程直到 \(b = 0\)。
上代码!
#include <bits/stdc++.h>
using namespace std;
long long a, b, k;
long long qpower(long long a, long long b, long long c) {
long long ans = 1, sum = a;
while (b > 0) {
if (b & 1) ans *= sum; ans %= c;
sum *= sum;
sum %= c;
b >>= 1;
}
return ans%c;
}
int main() {
scanf("%lld %lld %lld", &a, &b, &k);
printf("%lld^%lld mod %lld=%lld", a, b, k, qpower(a, b, k));
return 0;
}
矩阵快速幂
#include <bits/stdc++.h>
using namespace std;
#define ll long long
const int MOD = 1e9 + 7;
ll n, k2;
struct mrt{
ll m[101][101];
void read() {
for (int i = 1; i <= 100; ++i) {
for (int j = 1; j <= 100; ++j) m[i][j] = 0;
}
int x;
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= n; ++j) scanf("%d", &x), m[i][j] = x;
}
void print() {
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= n; ++j) printf("%d ", m[i][j]);
puts("");
}
}
};
mrt s, e, y;
mrt mc(mrt a, mrt b) {
mrt c;
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= n; ++j) c.m[i][j] = 0;
for (int i = 1; i <= n; ++i) {
for (int j = 1; j <= n; ++j) {
for (int k = 1; k <= n; ++k) {
c.m[i][j] = (c.m[i][j] + (a.m[i][k] * b.m[k][j]) % MOD) % MOD;
}
}
}
return c;
}
mrt mqpower(mrt a, ll b) {
if (b <= 1) return a;
mrt ans;
for (int i = 1; i <= n; ++i) {
ans.m[i][i] = 1;
}
while (b > 0) {
if (b & 1) ans = mc(a, ans);
a = mc(a, a);
b >>= 1;
}
return ans;
}
int main() {
scanf("%lld %lld", &n, &k2);
s.read();
mqpower(s, k2).print();
return 0;
}
只需要把乘号变成矩阵的运算就行了。
矩阵运算公式:
\[A \times B = C\]
确切的说是:
\[C_{i, j} = \sum _k^n A_{i, k} \times B_{k,j}\]
\(n\) 为矩阵大小
矩阵 \(C\) 的大小为 \(A\) 的宽与 \(B\) 的长
值得一提的是应先将快速幂中返回的矩阵赋值为单位矩阵(对角线为 \(1\) )再计算 \(k\) 次快速幂