阅读前请先掌握矩阵乘法的运算规则(自行百度
从易到难,从题目中学习
先掌握矩阵乘法,以及快速幂的写法
乘法,三层for循环,按照矩阵乘法规则写就行,快速幂就是普通快速幂板子
注意点:快速幂里,ans需要先定义为单位矩阵,结构体里二维数组需要初始化
矩阵左乘,不具有交换律 base * ans != ans * base
#include <iostream>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
using namespace std;
#define IOS ios::sync_with_stdio(false);cin.tie(0)
#define _for(i,s,b) for(int i=(s) ;i<=(b) ;i++)
#define _rep(i,s,b) for(int i=(s) ;i>=(b) ;i--)
#define mst(x,y) memset(x,y,sizeof(x))
#define all(v) v.begin() , v.end()
#define pb(v) push_back(v)
#define INF 0x3f3f3f3f
#define int long long
#define lson p*2,l,mid
#define rson p*2+1,mid+1,r
typedef long long ll;
int n,k;
const int N =105;
const int md = 1e9+7;
struct matrix
{
ll a[N][N]={0};
matrix operator * ( matrix &b)//重定义矩阵乘法
{
matrix d;
_for(i,1,n)
{
_for(j,1,n)
{
_for(k,1,n)
{
d.a[i][j] = (d.a[i][j] + a[i][k] * b.a[k][j]%md ) %md;
}
}
}
return d;
}
};
matrix qsm(matrix a,int k)//矩阵快速幂
{
matrix ans, temp=a;
mst(ans.a,0);
_for(i,1,n) ans.a[i][i] = 1;//建造单位矩阵
while( k )
{
if( k & 1) ans = (ans * temp ) ;
temp = ( temp * temp );
k>>=1;
}
return ans;
}
signed main()
{
matrix x,y,z;
cin>>n>>k;//输入n*n矩阵,k次幂
_for(i,1,n)
_for(j,1,n) cin>>x.a[i][j];
x= qsm(x,k);
_for(i,1,n)
{
_for(j,1,n)
cout<<x.a[i][j]<<" ";
cout<<endl;
}
return 0;
}
一般用于递推式里,不需要一项一项推,只要知道函数关系式,推出矩阵然后矩阵快速幂一下就行,O(N)变O(logn);
#include <iostream>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
using namespace std;
#define IOS ios::sync_with_stdio(false);cin.tie(0)
#define _for(i,s,b) for(int i=(s) ;i<=(b) ;i++)
#define _rep(i,s,b) for(int i=(s) ;i>=(b) ;i--)
#define mst(x,y) memset(x,y,sizeof(x))
#define all(v) v.begin() , v.end()
#define pb(v) push_back(v)
#define INF 0x3f3f3f3f
#define int long long
#define lson p*2,l,mid
#define rson p*2+1,mid+1,r
typedef long long ll;
int n=3;
const int N =105;
const int md = 1e9+7;
struct matrix
{
ll a[N][N]={0};
matrix operator * ( matrix &b)//重定义矩阵乘法
{
matrix d;
mst(d.a,0);//记得初始化
_for(i,1,n)
{
_for(j,1,n)
{
_for(k,1,n)
{
d.a[i][j] = (d.a[i][j] + a[i][k] * b.a[k][j]%md ) %md;
}
}
}
return d;
}
}ans,base;
matrix qsm(matrix a,int k)//矩阵快速幂
{
matrix ans, temp=a;
mst(ans.a,0);
_for(i,1,n) ans.a[i][i] = 1;//建造单位矩阵
while( k )
{
if( k & 1) ans = (ans * temp ) ;
temp = ( temp * temp );
k>>=1;
}
return ans;
}
signed main()
{
IOS;
int T;
cin>>T;
while( T-- )
{
mst(base.a,0);
base.a[1][1]=1;
base.a[1][3]=1;
base.a[2][1]=1;
base.a[3][2]=1;
mst(ans.a,0);
_for(i,1,3) ans.a[i][1]=1;
int x;
cin>>x;
if( x<=3 ) {cout<<1<<endl;continue;}
base = qsm(base,x-3);
ans = base * ans ;//注意矩阵左乘,不具有交换律
cout<<ans.a[1][1]<<endl;
}
}
会了矩阵加速,来个入门实战,用这个方法推肥波就很舒服了。
相比于直接递推,矩阵加速节省了内存,减少了时间,可谓利器,用递推的话,这题铁re
#include <iostream>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
using namespace std;
#define IOS ios::sync_with_stdio(false);cin.tie(0)
#define _for(i,a,b) for(int i=(a) ;i<=(b) ;i++)
#define _rep(i,a,b) for(int i=(a) ;i>=(b) ;i--)
#define mst(x,y) memset(x,y,sizeof(x))
#define all(v) v.begin() , v.end()
#define pb(v) push_back(v)
#define INF 0x3f3f3f3f
#define int long long
#define lson p*2,l,mid
#define rson p*2+1,mid+1,r
typedef long long ll;
const int N = 3;
const int mod = 1e9+7;
int n;
struct mat
{
ll a[N][N]={0};
mat operator * (const mat & b)
{
mat res;
_for(i,1,2)
{
_for(j,1,2)
{
_for(k,1,2)
{
res.a[i][j] = (res.a[i][j] + a[i][k] * b.a[k][j]%mod)%mod;
}
}
}
return res;
}
}ans,base;
mat qsm(mat a, ll k)
{
mat ans , temp = a;
mst(ans.a,0);
_for(i,1,3) ans.a[i][i] =1;
while( k )
{
if( k & 1) ans = ans * temp ;
temp = temp * temp ;
k>>=1;
}
return ans;
}
signed main()
{
//!!!!!!!!!!!!!!!!!!!!!!
// freopen("data.txt","r",stdin);
//!!!!!!!!!!!!!!!!!!!!!!
IOS;
mst(base.a,0);
mst(ans.a,0);
base.a[1][1]=1;
base.a[1][2]=1;
base.a[2][1]=1;
ans.a[1][1]=1;
ans.a[2][1]=1;
cin>>n;
if( n<=2 )
{
cout<<1<<endl;
return 0;
}
base = qsm(base , n-1);
ans = ans * base;
cout<<ans.a[1][1]<<endl;
}
思路:dp,矩阵乘优化(为了学个矩阵乘溯源两天
dp[i][j]表示第i年年龄为j的小鸡的数量
转移方程
j=0 dp[i][0] = dp[i-1][k] 今年出生的小鸡是去年1 ~ t-2 的小鸡数量
j!=0 dp[i][j] = dp[i-1][j-1]今年j岁的小鸡数量等于去年j-1岁的小鸡数量
做到这里只能过45%,后面会tle,考虑矩阵加速一下
推一下矩阵式,设t=4,也就是小鸡年龄在[0,3]间,设初始小鸡的年龄矩阵为(这里设为1列矩阵)
x,y,z,a分别对应年龄为0,1,2,3的小鸡数量,推下一年的年龄矩阵为
sum = x + y + z
从而推得递推矩阵
//dp,矩阵乘
#include <iostream>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
using namespace std;
#define IOS ios::sync_with_stdio(false);cin.tie(0)
#define _for(i,a,b) for(int i=(a) ;i<=(b) ;i++)
#define _rep(i,a,b) for(int i=(a) ;i>=(b) ;i--)
#define mst(x,y) memset(x,y,sizeof(x))
#define all(v) v.begin() , v.end()
#define pb(v) push_back(v)
#define INF 0x3f3f3f3f
#define int long long
#define lson p*2,l,mid
#define rson p*2+1,mid+1,r
#define int long long
typedef long long ll;
const int N = 75;
int mod;
int n,m,t;
struct mat
{
ll a[N][N]={0};
mat operator * (const mat & b)
{
mat res;
_for(i,0,t)
{
_for(j,0,t)
{
_for(k,0,t)
{
res.a[i][j] = (res.a[i][j] + a[i][k] * b.a[k][j]%mod)%mod;
}
}
}
return res;
}
}ans,base;
mat qsm(mat a, ll k)
{
mat ans , temp = a;
mst(ans.a,0);
_for(i,0,t-1) ans.a[i][i] =1;
while( k )
{
if( k & 1) ans = ans * temp ;
temp = temp * temp ;
k>>=1;
}
return ans;
}
ll gcd(ll a, ll b)
{
return b==0?a:gcd(b,a%b);
}
signed main()
{
//!!!!!!!!!!!!!!!!!!!!!!
// freopen("data.txt","r",stdin);
//!!!!!!!!!!!!!!!!!!!!!!
IOS;
cin>>n;
_for(i,1,n)
{
int x;
cin>>x;
ans.a[x][0]++;
}
cin>>t>>m>>mod;
//ini
_for(i,1,t-1)
{
base.a[i][i-1]=1;
}
_for(i,1,t-2)
{
base.a[0][i] = 1;
}
base = qsm( base , m-1);
ans = base * ans;
ll res = 0;
_for(i,0,t-1)
{
res = (res + ans.a[i][0])%mod;
}
cout<<res<<endl;
}