普通快速幂以及矩阵快速幂模板

  对于一个运算:求a的n次幂,我们知道最暴力的方法就是开一个变量ans,赋值为1,然后对ans乘以a n次,就可以得到答案。但是如果这个n很大,时间复杂度就会变高,这事我们就会想要优化时间复杂度,于是就引出了快速幂。快速幂的原理就是对n就行二进制拆分,假如n=10,二进制是1010,那么a^2*a^8就可以得到a^10,这样我们就不在一个一个的乘,而是先让a自乘一次得到a^2,把a^2乘给ans,然后再让a自乘两次得到a^8(a^2*a^2=a^4,a^4*a^4=a^8),再把a^8乘给ans就可以得到a^10了,这样我们的复杂度就降到了logn级别。而具体实现时就是判断n的最后一位如果是1就把当前自乘出来的a乘给ans,否则a直接自乘然后n除以2

  模板:

	while(n)
	{
		if(p&1)ans=ans*a%k;//实际运算时数很大,都会对一个数进行取模
		a=a*a%k; //因为a本身就是a^1,所以第一次运算时我们先判断有没有a^1有的话直接乘上去再自乘,自乘完毕就变成了n^2,所以下一次循环还是要先判断有没有这一位,有的话先乘上去在自乘,每一次都是这样
		n>>=1;
	}

  矩阵快速幂和这个的原理是一样的,对n进行二进制拆分,不同的是每次的自乘和往ans上乘的运算需要自己来写,模板

#include<iostream>
#include<cstdio>
#define ll long long
using namespace std;
const int mod=1e9+7;
const int maxn=105;
int n; 
ll k;
int a[maxn][maxn];
int ans[maxn][maxn],tmp[maxn][maxn];
void chengans()
{
	for(int i=1;i<=n;++i)
		for(int j=1;j<=n;++j)
			for(int k=1;k<=n;++k)
			{
				tmp[i][j]=(tmp[i][j]+(ll)a[i][k]*ans[k][j]%mod)%mod;
			}
	for(int i=1;i<=n;++i)
		for(int j=1;j<=n;++j)
			ans[i][j]=tmp[i][j],tmp[i][j]=0;
}
void zicheng()
{
	for(int i=1;i<=n;++i)
		for(int j=1;j<=n;++j)
			for(int k=1;k<=n;++k)
				tmp[i][j]=(tmp[i][j]+(ll)a[i][k]*a[k][j]%mod)%mod;
	for(int i=1;i<=n;++i)
		for(int j=1;j<=n;++j)
			a[i][j]=tmp[i][j],tmp[i][j]=0; 
}
int main()
{
	scanf("%d%lld",&n,&k);
	for(int i=1;i<=n;++i)
		for(int j=1;j<=n;++j)
			scanf("%d",&a[i][j]),ans[i][j]=a[i][j];
	k--;//矩阵的运算有一点点特殊,ans数组一开始得赋值成原始数组,这样就相当于一开始就已经乘了一次原始矩阵了,所以指数减一再去运算才是所求答案
	while(k)
	{
		if(k&1)chengans();
		zicheng ();
		k>>=1;
	}
	for(int i=1;i<=n;++i)
	{
		for(int j=1;j<=n;++j)
			printf("%d ",ans[i][j]);
		printf("
");
	}	
	return 0;
} 

  

原文地址:https://www.cnblogs.com/yuelian/p/11485963.html