矩阵加速快速幂模板

一、矩阵加速

1.思路

1.先根据题目要求初始化一个原始矩阵f[N]

2.为了使f[i]*[    ]=f[i+1],我们需要为其构建一个矩阵a[N][N](ps:最重要的一步)

3.利用分治快速幂或者二进制快速幂进行优化(ps:注意(n-1)次幂)

2.矩阵乘法

(1)定义

设A为 n*r 的矩阵,B为r*m 的矩阵,那么称n*m 的矩阵C为矩阵A与B的乘积,记作C=A*B ,例如

(2)基本性质

1.任何矩阵乘 0 得 0:0*A=A*0=0

2.结合律:A(BC)=(AB)C

3. 左分配律:A(B+C)=AB+AC

   右分配律:(B+C)A=BA+CA

4.矩阵乘法在以下两种情况下满足交换律

   (1).A和伴随矩阵相乘满足交换律

 (2)A和单位矩阵或数量矩阵满足交换律

二、相关例题

A、P1962 斐波那契数列

一、题目要求

大家都知道,斐波那契数列是满足如下性质的一个数列:

Fn​=1   (n≤2)

Fn=Fn−1​+Fn−2​   (n≥3)​

请你求出 Fn  mod 109+7的值。

输入格式

一行一个正整数 n

输出格式

输出一行一个整数表示答案。

输入输出样例

输入

5

输出 

5

输入 

10

输出

55

说明/提示

【数据范围】
对于 60% 的数据,1≤n≤92;
对于 100% 的数据,1≤n<263。

二、思路

1.因为n<=2时,f[n]=1,由此可以创建初始矩阵F[2]={1,1};

2.我们需要创建一个矩阵a[N][N],来使f[i]*[   ]=f[i+1];

3.利用快速幂模板

三、代码

1.第一种

#include<bits/stdc++.h>
#define endl '\n'
#define int long long
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
using namespace std;
const int N=2;
const int mod=1e9+7;
const int inf=0x3f3f3f3f;
int n;
void mul(int c[N][N],int b[N][N],int a[N][N])
{
	int t[N][N];
	memset(t,0,sizeof(t));
	int i,j,k;
	for(i=0;i<2;i++)
	{
		for(j=0;j<2;j++)
		{
			for(k=0;k<2;k++)
			{
				t[i][j]=(t[i][j]+a[i][k]*b[k][j])%mod; 
			}
		}
	}
	memcpy(c,t,sizeof(t));
}
void solve()
{
	cin>>n;
	n--;//(n-1)幂 
	int f[N][N]={1,1};
	int a[N][N]={{0,1},{1,1}};
	while(n)
	{
		if(n&1) mul(f,a,f);//把a和f的矩阵给f
		mul(a,a,a);//把a和a的矩阵给a
		n>>=1; 
    } 
    cout<<f[0][0]<<endl;
}
signed main()
{
	int t=1;
    while(t--)
    {
       solve();
    }
    return 0;
}
/*
void *memcopy(void *dest,const void *src,size_t count);
dest:目标空间地址
src:要拷贝内容空间源地址
count:拷贝内容字节数 
*/ 

2.第二种

#include<bits/stdc++.h>
#define endl '\n'
#define int long long
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
using namespace std;
const int N=1e6+10;
const int inf=0x3f3f3f3f;
const int mod=1e9+7;
int n;
struct juzhen
{
	int m[3][3];
}ans,base,temp;
juzhen mul(juzhen x,juzhen y)
{
	juzhen cnt;
	int i,j,k;
	for(i=1;i<=2;i++)
	{
		for(j=1;j<=2;j++)
		{
			int ans=0;
			for(k=1;k<=2;k++)
			{
				ans+=(x.m[i][k]*y.m[k][j])%mod;//c[i][j]=a[i][k]*b[k][j];(1<=k<=n)
				ans=ans%mod;
			}
			cnt.m[i][j]=ans;
		}
	}
	return cnt;
}
juzhen pow(int x)
{
	if(x==0)
	{
		temp.m[1][1]=1;
		temp.m[1][2]=0;
		temp.m[2][1]=0;
		temp.m[2][2]=1;
		return temp;
	}
	if(x==1)
	    return base;
	if(x%2==1)
	{
		juzhen xm=pow((x-1)/2);
		return mul(mul(xm,xm),base);
	}
	else
	{
		juzhen xm=pow(x/2);
		return mul(xm,xm);
	}
	
}
void solve()
{
	cin>>n;
	base.m[1][1]=0;
	base.m[1][2]=base.m[2][1]=base.m[2][2]=1;
	ans=pow(n-1);
	cout<<ans.m[2][2]<<endl;
}
signed main()
{
    int t=1;
    while(t--)
    {
       solve();
    }
    return 0;
}
/*
假设 1*2矩阵  A  f[i-2] f[i-1]  
构造 2*2矩阵  B  f[i-2] f[i-1]
            f[i-1]  0     1
            f[i]    1     1
新的1*2矩阵   C  f[i-2] f[i];
c[1][1]=f[i-1]
c[1][2]=f[i-1]+f[i-2]=f[i]
1.分治快速幂
a*a*a....*a;(n个a相乘) 
a*a...(n/2个a相乘)*a*a...(n/2个a相乘)
(a^(n/2))^2=a^n; 
        
*/

B、P1939 【模板】矩阵加速(数列)

一、题目要求

已知一个数列 a,它满足:

a[x]=1 x∈{1,2,3}

a[x]=a[x-1]​+a[x-3]​​  x≥4​

求 a 数列的第 n 项对 10^9+7 取余的值。

输入格式

第一行一个整数 T,表示询问个数。

以下 T 行,每行一个正整数 n。

输出格式

每行输出一个非负整数表示答案。

输入输出样例

输入

3
6
8
10

输出 

4
9
19

说明/提示

  • 对于 30%的数据 n≤100;
  • 对于 60% 的数据 n≤2×10^7;
  • 对于 100% 的数据 1≤T≤100,1≤n≤2×10^9

二、思路

1.f[3]={1,1,1}

2.创建a[3][3]

三、代码

1.第一种

#include<bits/stdc++.h>
#define endl '\n'
#define int long long
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
using namespace std;
const int N=3;
const int inf=0x3f3f3f3f;
const int mod=1e9+7;
int n;
void mul(int c[N][N],int b[N][N],int a[N][N])
{
	int t[N][N];
	memset(t,0,sizeof(t));
	int i,j,k;
	for(i=0; i<3; i++)
	{
		for(j=0; j<3; j++)
		{
			for(k=0; k<3; k++)
			{
				t[i][j]=(t[i][j]+a[i][k]*b[k][j])%mod;
			}
		}
	}
	memcpy(c,t,sizeof(t));
}
void solve()
{
	int i,j;
	int f[N][N]= {1,1,1};//这两句必须初始化
	int	a[N][N]= {{0,0,1},{1,0,0},{0,1,1}};
	cin>>n;
	n--;
	while(n)
	{
		if(n&1)
			mul(f,a,f);
		mul(a,a,a);
		n>>=1;
	}
	cout<<f[0][0]<<endl;
}
signed main()
{
	IOS;
	int t;
	cin>>t;
	while(t--)
	{
		solve();
	}
	return 0;
}

第二种 

#include<bits/stdc++.h>
#define endl '\n'
#define int long long
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0);
using namespace std;
const int N=2e5+10;
const int inf=0x3f3f3f3f;
const int mod=1e9+7;
int n;
struct juzhen
{
	int m[4][4];
}base,temp,ans;
juzhen mul(juzhen x,juzhen y)
{
	juzhen cnt;
	int i,j,k;
	for(i=1;i<=3;i++)
	{
		for(j=1;j<=3;j++)
		{
			int ans=0;
			for(k=1;k<=3;k++)
			{
				ans+=(x.m[i][k]*y.m[k][j])%mod;
				ans=ans%mod;
			}
			cnt.m[i][j]=ans;
		}
	} 
	return cnt;
} 
juzhen pow(int x)
{
	if(x==0)
	    return temp;
	if(x==1)
	    return base;
	if(x%2==1)
	{
		juzhen xm=pow((x-1)/2);
		return mul(mul(xm,xm),base);
	}
	else
	{
		juzhen xm=pow(x/2);
		return mul(xm,xm);
	}
}
void solve()
{
	cin>>n;
	ans=pow(n-1);
	cout<<(ans.m[1][1]+ans.m[2][1]+ans.m[3][1])%mod<<endl;
}
signed main()
{
    int t;
    cin>>t;
    memset(base.m,0,sizeof(base.m));
	memset(temp.m,0,sizeof(temp.m));
	base.m[1][3]=base.m[2][1]=base.m[3][2]=base.m[3][3]=1;
	temp.m[1][1]=temp.m[2][2]=temp.m[3][3]=1;
    while(t--)
    {
       solve();
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值