【学习笔记】矩阵快速幂

算法介绍

前置芝士:矩阵 矩阵乘法
这两个芝士并不是很难
重点可能在应用方面

首先介绍我所理解的广义的矩阵乘法:现在我们手上有两个矩阵\(A\)\(B\),我们期望得到一个答案矩阵\(Ans\) 其中\(Ans[i][j]\ =\ Ans[i][j]\ +\ (A[i][k]\ *\ B[i][k]) 其中 +\ * 代一种运算(如 min\ max 等等)\)
都可以用矩阵快速幂把递推的时间从\(O(n)减到O(logn)\)

先放一下矩阵快速幂的代码吧 类比快速幂即可

#include<iostream>
#include<cstdio>
#include<cstring>
#define ll long long
#define MOD 1000000007
using namespace std;

ll m,k;

inline ll read(){
	ll f = 1,ans = 0;
	char a = getchar();
	while((a < '0' || a > '9') && a != '-') a = getchar();
	if(a == '-') f = -1,a = getchar();
	while(a <= '9' && a >= '0') ans = (ans << 3) + (ans << 1) + (a ^ 48),a = getchar();
	return f * ans;
} 

struct map{
	ll a[200][200];
	map(){
		memset(a,0,sizeof(a));
	}
	void in(){
		for(ll i = 1;i <= m;i++)
		for(ll j = 1;j <= m;j++)
		a[i][j] = read();
	}
	void out(){
		for(ll i = 1;i <= m;i++,puts(""))
		for(ll j = 1;j <= m;j++)
		cout<<a[i][j]<<" ";
	}
}ai,ans;

map operator * (const map &a,const map &b){
	map c;
	for(ll k = 1;k <= m;k++)
	for(ll i = 1;i <= m;i++)
	for(ll j = 1;j <= m;j++)
	c.a[i][j] = (c.a[i][j] + (a.a[i][k] * b.a[k][j]) % MOD)% MOD;
	return c;
}

void quick(ll k){
	while(k){
		if(k & 1) ans = ans * ai;
		ai = ai * ai;
		k >>= 1;
	}
}
int main(){
	m = read();
	k = read() - 1;
	ai.in();
	ans = ai;
	quick(k);
	ans.out();
}

例题

前面说了 矩阵快速幂重点在于应用
下面给出两种我最近见到的题

构造矩阵

P1939 【模板】矩阵加速(数列)
根据题目,我们的目标矩阵是这样的

\[ \begin{matrix} f[i] \\ f[i - 1] \\ f[i - 2] \end{matrix} \]

然后我们发现

\[ \begin{matrix} f[i]=f[i−1]×1+f[i−2]×0+f[i−3]×1 \\ f[i−1]=f[i−1]×1+f[i−2]×0+f[i−3]×0 \\ f[i−2]=f[i−1]×0+f[i−2]×1+f[i−3]×00 \end{matrix} \]

观察系数 我们构造出这样一个递归矩阵

\[ \begin{matrix} 1 & 0 & 1 \\ 1 & 0 & 0 \\ 0 & 1 & 0 \end{matrix} \]

接下来就是套路的快速幂了

#include<iostream>
#include<cstdio>
#include<cstring>
#define ll long long
#define MOD 1000000007
using namespace std;

ll m = 3,k,T;

inline ll read(){
	ll f = 1,ans = 0;
	char a = getchar();
	while((a < '0' || a > '9') && a != '-') a = getchar();
	if(a == '-') f = -1,a = getchar();
	while(a <= '9' && a >= '0') ans = (ans << 3) + (ans << 1) + (a ^ 48),a = getchar();
	return f * ans;
} 

struct map{
	ll a[200][200];
	map(){
		memset(a,0,sizeof(a));
	}
	void aiin(){
		memset(a,0,sizeof(a));		
		a[1][1] = a[1][3] = a[2][1] = a[3][2] = 1;
	}
	void ansin(){
		memset(a,0,sizeof(a));
	    a[1][1] = a[2][2] = a[3][3] = 1; 
	}
}ai,ans;

map operator * (const map &a,const map &b){
	map c;
	for(ll k = 1;k <= 3;k++)
	for(ll i = 1;i <= 3;i++)
	for(ll j = 1;j <= 3;j++)
	c.a[i][j] = (c.a[i][j] + (a.a[i][k] * b.a[k][j]) % MOD)% MOD;
	return c;
}

void quick(ll k){
	ans.ansin();
	ai.aiin();
	while(k){
		if(k & 1) ans = ans * ai;
		ai = ai * ai;
		k >>= 1;
	}
}
int main(){
	T = read();
	while(T --){
		k = read();
		if(k <= 3)
		{puts("1");continue;} 
		else
		quick(k),cout<<ans.a[2][1]<<endl;
	} 
}

题目自带的矩阵

P2886 [USACO07NOV]Cow Relays G
题目大意算法就不再阐述 请看这里

posted @ 2020-10-19 20:48  fhq_treap  阅读(105)  评论(0编辑  收藏  举报