矩阵快速幂
快速幂
再讲矩阵之前想要来做一下铺垫,什么是快速幂,我们知道2的n次方要用o(n)的时间求解,太慢了,我们可以每一次让次数除以二,底数平方,每一次当指数为奇数的时候,就把ans=ans*base,这样就可以用o(logn )的时间求出一个指数的值
小细节
这里注意一下,假如是要mod一个比较小的数的话,最开始的base可能回比这个mod要大,假如一进来不先模的话会出问题
代码如下
#define ll long long
ll fast(ll b,int p){
ll ansl = 1;
b %= mod;//这里注意一下
while(p){
if(p % 2 == 1){
ansl = ansl * b;
ansl %= mod;
}
b = b * b;
b %= mod;
p = p / 2;
}
return ansl % mod;
}
矩阵
矩阵说白了就是一个二维数组,
就差不多长这样,我们定义乘法就是c[i][j]=singema a[i][k]*b[k][j]也就是一个矩阵行上每一个数,和另一个矩阵列上对应位置相乘的和,写成代码就是
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
for(int k=1;k<=n;k++
c[i][j]=(c[i][j]+(a[i][k]*b[k][j])%mod)%mod;
如果不需要取模运算就不用加上“%”了。
至于矩阵的幂运算,我们可以用快速幂的思想去优化,也就是
struct ju{
m[1000][1000];
};
ju fast(ju a,int po,int n){
ju c;
memset(c.m,0,sizeof(c.m));
for(int i=1;i<=n;i++) c[i][i]=1;//构造单位矩阵
while(po){
if(po%2==1){
c=mul(c,a,n);//就是上面的乘法运算
}
po/=2;
a=mul(a,a,n);
}
return c;
}
这就是矩阵快速幂的基本实现,现在我们来看看它可以干什么。
应用
主要通过把数放到矩阵的不同位置,然后把普通递推式变成"矩阵的等比数列",最后快速幂求解递推式
最简单的可能就是去求斐波那契数列,矩阵很好想,下面是代码实现
#include<bits/stdc++.h>
using namespace std;
#define mm 10000000007
const int mod = 1000000007;
long long n1;
struct ju{
long long m[3][3];
};
ju yuan;
ju chu;
ju mul(ju a,ju b,int n){
ju c;
memset(c.m,0,sizeof(c.m));
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;
}
}
}
return c;
}
ju ans;
ju fast(ju a,long long po,int n){
memset(ans.m,0,sizeof(ans.m));
for(int i=1;i<=n;i++){
ans.m[i][i]=1;
}
while(po){
if(po%2==1){
ans=mul(ans,a,n);
}
po/=2;
a=mul(a,a,n);
}
return ans;
}
int main(){
scanf("%lld",&n1);
yuan.m[1][1]=1;
yuan.m[1][2]=1;
yuan.m[2][1]=1;
yuan.m[2][2]=0;
chu.m[1][1]=1;
chu.m[2][1]=1;
if(n1<=2) {
printf("1");
return 0;
}
yuan=fast(yuan,n1-2,2);
chu=mul(yuan,chu,2);
printf("%lld",chu.m[1][1]%mod);
return 0;
}
一定要注意初始化的值不要错,并且在函数里定义的变量一定要初始化,要不然会有奇怪的错误。