一、矩阵加速
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;
}