之前对于快速幂,只知道怎么用,却没弄清楚什么原理,在学了计算机组成原理和计算机网络后对二进制敏感了许多,如8255,直接求的话就要执行255次乘法,当指数很大的时候,就会变得很慢;
255用二进制表示就是八个1,1111 1111,
实际上255 = 28 * 1 + 27 * 1 + 26 * 1 + 25 * 1 + 24 * 1 + 23 * 1 + 22 * 1 + 21 * 1 + 20 * 1 = 128 + 64 + 32 + 16 + 8 + 4 + 2 + 1 + 0
我们把指数转变为二进制表示:
8(11111111) = 8128*1 * 864*1 * 832*1 * 816*1 * 88*1 * 84*1 * 82*1 * 81*1 * 80*1,从右往左开始计数,指数分别为 128、64、32、16、8、4、2、1因为当前指数是上一个指数的两倍,所以当前要乘的数=上一个乘数*上一个乘数,当前这个乘数是否与ans相乘,就要看当前位于的二进制数是否为1,采用快速幂所需乘法次数就大大减少。
如果数大,题目要求取模,就每次取模。
#include
using namespace std;
int qpow(int a, int b, int mod){
int ans = 1, tmp = a;
while(b){
if(b & 1){
ans = ans * tmp % mod;
}
tmp = tmp * tmp;
b = b >> 1;
}
return ans % mod;
}
int main()
{
int a, b;
scanf("%d %d", &a, &b);
printf("%d", qpow(a, b, 100));
return 0;
}
了解了快速幂,只需要再了解线性代数中矩阵的乘法,矩阵快速幂就肯定懂了。
#include
#include
using namespace std;
const int N = 1e2;
const int mod = 1e5;
struct abc{
int t[N][N];
}a, ans;
void init(){
for(int i = 1; i <= N; ++i){
ans.t[i][i] = 1;
}
}
struct abc x(struct abc a, struct abc b, int n){
struct abc c;
memset(c.t, 0, sizeof(c.t));
for(int i = 1; i <= n; ++i){
for(int j = 1; j <= n; ++j){
for(int k = 1; k <= n; ++k){
c.t[i][j] = (c.t[i][j] + (a.t[i][k] * b.t[k][j]) % mod) % mod;
}
}
}
return c;
}
int main()
{
int b, n;
scanf("%d %d", &b, &n);
for(int i = 1; i <= n; ++i){
for(int j = 1; j <= n; ++j){
scanf("%d", &a.t[i][j]);
}
}
init();
while(b){
if(b & 1){
ans = x(ans, a, n);
}
a = x(a, a, n);
b = b >> 1;
}
for(int i = 1; i <= n; ++i){
for(int j = 1; j <= n; ++j){
printf("%d ", ans.t[i][j]);
}
printf("\n");
}
return 0;
}