菜鸟的快速幂理解

之前对于快速幂,只知道怎么用,却没弄清楚什么原理,在学了计算机组成原理和计算机网络后对二进制敏感了许多,如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;
}

你可能感兴趣的:(数论)