矩阵快速幂加速递推

P3390 【模板】矩阵快速幂#

矩阵乘法:

ci,j=ai,kbk,j

矩阵快速幂:与普通快速幂类似。

特殊地,定义 A0 为单位矩阵 I=[100010001]

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>

using namespace std;
using i64 = long long;

const int N = 110, mod = 1e9 + 7;

struct matrix {
	matrix() { memset(a, 0, sizeof(a)); }
	int a[N][N];
};

int n;
i64 k;

matrix operator*(matrix& a, matrix& b) {
	matrix c;
	for (int k = 1; k <= n; k++)
		for (int i = 1; i <= n; i++)
			for (int j = 1; j <= n; j++)
				c.a[i][j] = (c.a[i][j] + 1ll * a.a[i][k] * b.a[k][j]) % mod;
	return c;
}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
	
	cin >> n >> k;
	
	matrix ans, b;
	
	for (int i = 1; i <= n; i++) ans.a[i][i] = 1;
	
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= n; j++)
			cin >> b.a[i][j];
	
	while (k) {
		if (k & 1) ans = ans * b;
		b = b * b;
		k >>= 1;
	}
	
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= n; j++) cout << ans.a[i][j] << ' ' ;
		cout << '\n';
	}
	return 0;
}

POJ-3070/P1962 斐波那契数列#

img

img

img

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>

using namespace std;
using i64 = long long;

const int N = 3, mod = 1e9 + 7;

struct matrix {
	matrix() { memset(a, 0, sizeof(a)); }
	int a[N][N];
};

matrix operator*(matrix& a, matrix& b) {
	matrix c;
	
	for (int i = 1; i < N; i++)
		for (int j = 1; j < N; j++)
			for (int k = 1; k < N; k++)
				c.a[i][j] = (c.a[i][j] + 1ll * a.a[i][k] * b.a[k][j]) % mod;
	
	return c;
}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
	
	matrix ans, b;
	i64 n;
	
	cin >> n;
	
	for (int i = 0; i < N; i++) ans.a[i][i] = 1;
	
	b.a[1][1] = 1;
	b.a[1][2] = 1;
	b.a[2][1] = 1;
	b.a[2][2] = 0;
	
	while (n) {
		if (n & 1) ans = ans * b;
		b = b * b;
		n >>= 1;
	}
	
	cout << ans.a[1][2] << '\n';
	return 0;
}

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

本题是斐波那契数列的进阶版。

因为 ax 的计算涉及三项:ax1ax2ax3

所以我们有

[axax1ax2]=[ax1ax2ax3]×A

A 应为:

A=[abcdefghi]

按照套路,可以解得:

A=[101100010]

所以原问题转化为 [ax+2ax+1ax]=[a3a2a1]×Ax

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>

using namespace std;

const int N = 4, mod = 1e9 + 7; 

struct matrix {
	matrix() { memset(a, 0, sizeof(a));	}
	int a[N][N];
};

matrix operator*(matrix& a, matrix& b) {
	matrix c;
	
	for (int i = 1; i < N; i++)
		for (int j = 1; j < N; j++)
			for (int k = 1; k < N; k++)
				c.a[i][j] = (c.a[i][j] + 1ll * a.a[i][k] * b.a[k][j]) % mod;
				
	return c;
}

void solve() {
	int n;
	cin >> n;
	
	matrix ans, b;
	
	for (int i = 0; i < N; i++) ans.a[i][i] = 1;
	
	b.a[1][1] = 1;
	b.a[1][2] = 1;
	b.a[2][3] = 1;
	b.a[3][1] = 1;
	
	while (n) {
		if (n & 1) ans = ans * b;
		b = b * b;
		n >>= 1;
	}
	
	memset(b.a, 0, sizeof(b.a));
	b.a[1][1] = 1;
	b.a[1][2] = 1;
	b.a[1][3] = 0;
	
	ans = b * ans;
	
	cout << ans.a[1][3] << '\n';
}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
	
	int T;
	
	cin >> T;
	while (T--) solve();
	
	return 0;
}

POJ 3233/UVA 11149 Power of Matrix#

image

以UVA的题目为例,POJ上的题目就是把solve()函数执行一遍即可。

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>

using namespace std;

const int N = 90, mod = 10;	

struct matrix {
	matrix() { memset(a, 0, sizeof(a));	}
	int a[N][N];
};

matrix operator*(matrix& a, matrix& b) {
	matrix c;
	
	for (int i = 1; i < N; i++)
		for (int j = 1; j < N; j++)
			for (int k = 1; k < N; k++)
				c.a[i][j] = (c.a[i][j] + a.a[i][k] * b.a[k][j]) % mod;
	
	return c;
}

int n, k;

void solve() {
	matrix ans, b;
	
	for (int i = 1; i <= (n << 1); i++) ans.a[i][i] = 1;
	
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= n; j++) {
			int x;
			cin >> x;
			x %= 10;
			b.a[i][j] = x;
			b.a[i][j + n] = 0;
			b.a[i + n][j] = x;
			if (i == j) b.a[i + n][j + n] = 1;
			else b.a[i + n][j + n] = 0;
		}
	}
	
	while (k) {
		if (k & 1) ans = ans * b;
		b = b * b;
		k >>= 1;
	}
	
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j < n; j++) {
			cout << ans.a[i + n][j] << ' ';
		}
		cout << ans.a[i + n][n] << '\n';
	}
	
	cout << '\n';
}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
	
	while (cin >> n >> k, (n && k)) solve();
	return 0;
}

P4910 帕秋莉的手环#

吐槽一句:题面写得太好了!!!

建议看翻译

本题先使用普通DP进行求解:

f[i][0/1] 为前 i1 位都已经选择好,且第 i 位染上了颜色 0/1的方案数。(设 1 为黑色,0 为白色。

于是有了:

f[i][1]=f[i1][0],

f[i][0]=f[i1][0]+f[i1][1]

而第一个珠子分为两种情况,黑的或白的,分别dp就可以了。

这种暴力dp可以拿 48 分,dalao们有的可以 AC

我们通过运算,不难发现,答案为:

fib[i] 为斐波那契数列的第 i 项。

ans=fib[n1]×2+fib[n]

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>

using namespace std;
using i64 = long long;

const int N = 3, mod = 1e9 + 7;

struct matrix {
	matrix() { memset(a, 0, sizeof(a));	}
	int a[N][N];
};

matrix operator*(matrix& a, matrix& b) {
	matrix c;
	for (int i = 1; i < N; i++)
		for (int j = 1; j < N; j++)
			for (int k = 1; k < N; k++)
				c.a[i][j] = (c.a[i][j] + 1ll * a.a[i][k] * b.a[k][j]) % mod;
	return c;
}

void solve() {
	i64 n;
	cin >> n;
	n--;
	
	matrix a, res;
	
	for (int i = 1; i < N; i++) res.a[i][i] = 1;
	
	a.a[1][1] = 1;
	a.a[1][2] = 1;
	a.a[2][1] = 1;
	a.a[2][2] = 0;
	
	while (n) {
		if (n & 1) res = res * a;
		a = a * a;
		n >>= 1;
	}
	cout << (res.a[1][2] * 2 % mod + res.a[1][1]) % mod << '\n';
}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
	
	int T;
	cin >> T;
	while (T--) solve(); 
	return 0;
}

P2886 [USACO07NOV]Cow Relays G#

题意:
给定一张 T 条边的无向连通图,求从 SE 经过 N 条边的最短路长度。


用邻接矩阵 M 表示一个图,M(i,j) 是其第 i 行第 j 列元素,表示点 i 和 点 j 的直接关系,若点 i 和点 j直连,令 M[i,j] 等于 ij 的权值,否则等于无穷大();当 i 等于 j 时令 M[i,i]=

定义矩阵的广义乘法:

M×M=mina=1N[M(i,a)+M(a,j)]

也就是把普通的矩阵乘法从求和改成了取最小值,把内部项相乘改为了相加。

定理: 计算邻接矩阵的广义幂 G=MnG(i,j) 的值是从 ij 经过 n 条边(或 n1 个点)的最短路径长度。

以上摘自 《算法竞赛》。


注意:在做矩阵乘法时,一定要处理好上界(代码中为 idx)。

#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <vector>

using namespace std;

const int N = 1010, M = 110;

int n, m;
int S, T;

int ver[N], idx;

int add(int a) {
	if (ver[a]) return ver[a];
	ver[a] = ++idx;
	return ver[a]; 
}

struct matrix {
	matrix() { memset(a, 0x3f, sizeof(a));	}
	int a[M][M];
};

matrix operator*(matrix& a, matrix& b) {
	matrix c;
	for (int k = 1; k <= idx; k++)
		for (int i = 1; i <= idx; i++)
			for (int j = 1; j <= idx; j++)
				c.a[i][j] = min(c.a[i][j], a.a[i][k] + b.a[k][j]);
	return c;
}

int main() {
	ios::sync_with_stdio(false);
	cin.tie(nullptr);
	
	matrix ans, g;
	cin >> n >> m >> S >> T;
	
	for (int i = 1; i <= m; i++)
	{
		int w, a, b, t1, t2;
		cin >> w >> a >> b;
		t1 = add(a);
		t2 = add(b);
		g.a[t1][t2] = g.a[t2][t1] = w;
	}
	
	n--;
	ans = g;
	
	while (n) {	
		if (n & 1) ans = ans * g;
		g = g * g;
		n >>= 1;
	}
	
	cout << ans.a[add(S)][add(T)] << '\n';
	return 0;
}

[参考文献]

《算法竞赛》

posted @   SunnyYuan  阅读(10)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 开源Multi-agent AI智能体框架aevatar.ai,欢迎大家贡献代码
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· AI技术革命,工作效率10个最佳AI工具
more_horiz
keyboard_arrow_up dark_mode palette
选择主题
menu
点击右上角即可分享
微信分享提示