从校赛了解到矩阵快速幂,一直没做总结。
先了解快速幂,矩阵快速幂的话需要一点矩阵知识。
快速幂时间复杂度为log(n),当n很大时,无疑减少了许多的时间 ,
直接点,比如:2的19次方,19可以转化为二进制:10011=2^3+2^1+2^0,只要做三次运算
上代码:(a的n次方)
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll quickpow(ll a,ll n)
{
ll temp=1;// 19的二进制为10011
while(n)
{
if(n&1)//转化为二进制数后,若最后一位为1
temp*=a;
n>>=1;//向右移动一位
a*=a;
}
return temp;
}
int main()
{
ll a,b;
scanf("%I64d %I64d",&a,&b);
ll ans=quickpow(a,b);
printf("%I64d\n",ans);
ll sum=pow(2,19);
printf("%I64d",sum);
return 0;
}
也可以换一种其他方式去理解,就是对指数n操作,当指数为奇数是,temp存放临时的底数,n减一,二分,a*a底数相乘,n/2
指数是偶数的时候直接a*a,n/2。
矩阵快速幂的话也是基于快速幂的基础上,直接例子吧:
求斐波那契数列的第n项,当n很大的时候,用普通的线性枚举是比较慢的。用矩阵的思想,
斐波那契数列f(n)=f(n-1)+f(n-2),eg: 0 1 1 2 3 5 8 13......,
利用矩阵
继续分解下去,
学习线性代数的同学们会想到将其矩阵对角化也是可以的,考虑到是计算机运算,也没什么关系吧......
即求矩阵1 1 1 0的(n-1)次方,附上代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll mod=1000000007;
typedef struct {
ll m[2][2];
//Matrix(){memset(m,0,sizeof(m));}
}Matrix;
Matrix p;
Matrix matrixmul(Matrix a,Matrix b)
{
int i,j,k;
Matrix c;
for(i=0;i<2;i++)
{
for(j=0;j<2;j++)
{
c.m[i][j]=0;
for(k=0;k<2;k++)
{
c.m[i][j]+=(a.m[i][k]*b.m[k][j])%mod;
c.m[i][j]%=mod;
}
}
}
return c;
}
Matrix quickpow(ll n)
{
Matrix hh=p;
Matrix b;
b.m[0][0]=1,b.m[1][1]=1;
b.m[0][1]=0,b.m[1][0]=0; //即b矩阵是单位矩阵,相当于快速幂的1
while(n)
{
if(n&1)
b=matrixmul(b,hh);
hh=matrixmul(hh,hh);
n/=2;
}
return b;
}
int main()
{
ll nn,i,j,T;
scanf("%lld",&T);
p.m[0][0]=1,p.m[0][1]=1,p.m[1][0]=1,p.m[1][1]=0;
while(T--)
{
scanf("%lld",&nn);
Matrix ans;
if(!nn)
{
printf("0");
continue;
}
ans=quickpow(nn-1);
printf("%lld\n",ans.m[0][0]);
}
return 0;
}
同理可以运用到其他的地方。