矩阵快速幂 题目整理 HDU5015、CF392 C、HDU4686、CF385 E

矩阵快速幂

例行公事先介绍下矩阵乘法~~(相信大家都会)~~

矩阵

  • 在数学中,矩阵(Matrix)是一个按照长方阵列排列的复数或实数集合。

矩阵乘法

  • 矩阵相乘只有在第一个矩阵的列数(column)和第二个矩阵的行数(row)相同时才有意义
  • 一个m×n的矩阵就是m×n个数排成m行n列的一个数阵
  • 由于它把许多数据紧凑的集中到了一起,所以有时候可以简便地表示一些复杂的模型,如电力系统网络模型

设A为 m ∗ p m*p mp的矩阵,B为 p ∗ n p*n pn的矩阵,那么称 m ∗ n m*n mn的矩阵C为矩阵A与B的乘积,记作 C = A B C = AB C=AB
其中矩阵C中的第 i 行第 j 列元素可以表示为:
C [ i ] [ j ] = ∑ k = 1 p a [ i ] [ k ] ∗ b [ k ] [ j ] = a [ i ] [ 1 ] ∗ b [ 1 ] [ j ] + a [ i ] [ 2 ] ∗ b [ 2 ] [ j ] + ⋯ + a [ i ] [ p ] ∗ b [ p ] [ j ] C[i][j]=\sum_{k=1}^{p}{a[i][k]*b[k][j]}=a[i][1]*b[1][j]+a[i][2]*b[2][j]+\cdots+a[i][p]*b[p][j] C[i][j]=k=1pa[i][k]b[k][j]=a[i][1]b[1][j]+a[i][2]b[2][j]++a[i][p]b[p][j]

  • 对于矩阵 C = A B C = AB C=AB ,矩阵A的第m行“乘上”矩阵B的第n列

精简板子

struct Matrix {
	LL n, m;
	LL v[maxn][maxn];
	Matrix(int n = 0, int m = 0) :n(n), m(m) {	//构造函数
		memset(v, 0, sizeof(v));
	}
	void clear() {	//重置函数
		memset(v, 0, sizeof(v));
	}
	void show() {	//debug函数
		for (int i = 1; i <= n; i++) {
			for (int j = 1; j <= m; j++)
				cout << v[i][j] << ' ';
			cout << '\n';
		}
	}
	friend Matrix operator *(const Matrix& a, const Matrix& b) {//乘法封装
		Matrix res(a.n, b.m);
		for (int i = 1; i <= a.n; i++)
			for (int j = 1; j <= b.m; j++)
				for (int k = 1; k <= a.m; k++)
					res.v[i][j] = (a.v[i][k] * b.v[k][j] % mod + res.v[i][j]) % mod;
		return res;
	}
};

矩阵快速幂

  • 所谓矩阵快速幂,即为使用快速幂的计算方式去计算相同矩阵连乘(即矩阵的幂)的结果
  • 前面已经讲过,可以将矩阵构造成结构体,重载运算符后就可以直接当做正常变量来使用了
void quickpow(Matrix& res, Matrix m, LL p) {
	while (p) {
		if (p & 1)
			res = res * m;
		m = m * m;
		p >>= 1;
	}
}

重点

以下为矩阵快速幂,常见的题目整理和公式

Fib数

( F i b ( 1 ) F i b ( 2 ) ) ∗ ( 0 1 1 1 ) \left(\begin{array}{ccc}Fib(1)&amp;Fib(2)\\\end{array}\right)*\left(\begin{array}{ccc}0&amp;1\\1&amp; 1\\\end{array}\right) (Fib(1)Fib(2))(0111) = = = ( F i b ( 2 ) F i b ( 1 ) + F i b ( 2 ) ) \left(\begin{array}{ccc} Fib(2)&amp;Fib(1)+Fib(2)\end{array}\right) (Fib(2)Fib(1)+Fib(2))

P3390 【模板】矩阵快速幂模板题

常用推导

在这里插入图片描述

HDU 5015 233 Matrix

题意

给出矩阵的第0行 ( 233 , 2333 , 23333 , ⋯ &ThinSpace; ) (233,2333,23333,\cdots) (233,2333,23333,)和第0列 a 1 , a 2 , ⋯ &ThinSpace; , a n a1,a2,\cdots,an a1,a2,,an ( n &lt; = 10 , m &lt; = 1 0 9 ) (n&lt;=10,m&lt;=10^9) (n<=10m<=109),给出式子: A [ i ] [ j ] = A [ i − 1 ] [ j ] + A [ i ] [ j − 1 ] A[i][j] = A[i-1][j] + A[i][j-1] A[i][j]=A[i1][j]+A[i][j1],要求 A [ n ] [ m ] A[n][m] A[n][m]

思路

较为复杂的一个推导

  • 可以假设未给出的第0行第0列值为23
  • 对于每一列,可以将所有元素一起构造成初始矩阵。
    在这里插入图片描述

CF392C Yet Another Number Sequence

题意

给定 n , k , F i b ( 1 ) = 1 , F i b ( 2 ) = 2 n,k,Fib(1)=1,Fib(2)=2 n,k,Fib(1)=1,Fib(2)=2,令 A k ( i ) = F i b ( i ) ∗ i k A_{k}(i)=Fib(i)*i^k Ak(i)=Fib(i)ik
∑ i = 1 n A k ( i ) \sum_{i=1}^{n}A_{k}(i) i=1nAk(i) ( k ≤ 40 ) (k\leq40) (k40)

思路

  • 本题的难点在于 i k i^k ik的推导
  • 以下表格展示使用二项式定理推导 i 3 i^3 i3的过程
1 0 1^0 10 1 1 1^1 11 1 2 1^2 12
C [ 0 ] [ 0 ] ∗ 1 0 = 2 0 C[0][0]*1^0=2^0 C[0][0]10=20 C [ 1 ] [ 0 ] ∗ 1 0 + C [ 1 ] [ 1 ] ∗ 1 1 = 2 1 C[1][0]*1^0+C[1][1]*1^1=2^1 C[1][0]10+C[1][1]11=21 C [ 2 ] [ 0 ] ∗ 1 0 + C [ 2 ] [ 1 ] ∗ 1 1 + C [ 2 ] [ 2 ] ∗ 1 2 = 2 2 C[2][0]*1^0+C[2][1]*1^1+C[2][2]*1^2=2^2 C[2][0]10+C[2][1]11+C[2][2]12=22
C [ 0 ] [ 0 ] ∗ 2 0 = 3 0 C[0][0]*2^0=3^0 C[0][0]20=30 C [ 1 ] [ 0 ] ∗ 2 0 + C [ 1 ] [ 1 ] ∗ 2 1 = 3 1 C[1][0]*2^0+C[1][1]*2^1=3^1 C[1][0]20+C[1][1]21=31 C [ 2 ] [ 0 ] ∗ 2 0 + C [ 2 ] [ 1 ] ∗ 2 1 + C [ 2 ] [ 2 ] ∗ 2 2 = 3 2 C[2][0]*2^0+C[2][1]*2^1+C[2][2]*2^2=3^2 C[2][0]20+C[2][1]21+C[2][2]22=32

HDU4686 Arc of Dream

题意

a i = a i − 1 ∗ a x + a y a_{i}=a_{i-1}*ax+ay ai=ai1ax+ay
b i = b i − 1 ∗ b x + b y b_{i}=b_{i-1}*bx+by bi=bi1bx+by
∑ i = 0 i &lt; n a i ∗ b i \sum_{i=0}^{i &lt; n} a_{i}*b_{i} i=0i<naibi

思路

本题难度在于 a i ∗ b i a_{i}*b_{i} aibi的推导
显然由 a i a_{i} ai b i b_{i} bi使用矩阵快速幂推导比较困难
但是由 a i ∗ b i , a i , b i a_{i}*b_{i},a_{i},b_{i} aibi,ai,bi推导就可以了
( a i ∗ a x + a y ) ∗ ( b i ∗ b x + b y ) = a x ∗ b x ∗ a i ∗ b i + b x ∗ a y ∗ b i + a x ∗ b y ∗ a i + a y ∗ b y (a_{i}*ax+ay)*(b_{i}*bx+by)=ax*bx*a_{i}*b_{i}+bx*ay*b_{i}+ax*by*a_{i}+ay*by (aiax+ay)(bibx+by)=axbxaibi+bxaybi+axbyai+ayby
( a i ∗ b i , a i , a y , b i , b y , s u m ) (a_{i}*b_{i},a_{i},ay,b_{i},by,sum) (aibi,ai,ay,bi,by,sum)为初始矩阵推导即可

CF385 E Bear in the Field

题意

有一片 n × n n×n n×n的草莓地,每个位置的初始草莓量为横坐标和纵坐标的和,然后每过一秒增长一个草莓
然后给出熊的初始位置 ( s x , s y ) (sx,sy) (sx,sy),以及移动的速度 ( d x , d y ) (dx,dy) (dx,dy),每一秒发生的事:

  • 速度增加k(k为该位置的草莓数)
  • 熊的位置发生移动
  • 每个位置上草莓数+1
    求t秒后熊的位置

思路

为了方便求余n,将坐标由 [ 1 , n ] [1,n] [1,n]变成 [ 0 , n − 1 ] [0,n-1] [0,n1]
在这里插入图片描述

233 Matrix 代码

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace  std;
#pragma warning (disable:4996)
typedef long long LL;
const int maxn = 13;
const LL mod = 10000007;
struct Matrix
{
	int n, m;
	int v[maxn][maxn];
	Matrix(int n = 0, int m = 0):n(n),m(m) {
		memset(v, 0, sizeof(v));
	}
	void clear() {
		memset(v, 0, sizeof(v));
	}
	void show() {
		for (int i = 1; i <= n; i++) {
			for (int j = 1; j <= m; j++)
				cout << v[i][j] << ' ';
			cout << '\n';
		}
	}
	friend Matrix operator *(const Matrix& a, const Matrix& b) {
		Matrix res(a.n, b.m);
		for (int i = 1; i <= a.n; i++)
			for (int j = 1; j <= b.m; j++)
				for (int k = 1; k <= a.m; k++)
					res.v[i][j] = (res.v[i][j] + LL(a.v[i][k]) * b.v[k][j] % mod) % mod;
		return res;
	}
};
void quickpow(Matrix &res, Matrix m, LL p) {
	while (p) {
		if (p & 1)
			res = res * m;
		m = m * m;
		p >>= 1;
	}
}
int main() {
	int n, m;
	while (~scanf("%d%d", &n, &m)) {
		Matrix a(1, n + 2), b(n + 2, n + 2);
		a.v[1][1] = 23;
		for (int i = 2; i <= n + 1; i++)
			scanf("%d", &a.v[1][i]);
		a.v[1][n + 2] = 3;
		for (int i = 1; i <= n + 2; i++)
			b.v[1][i] = 10, b.v[n + 2][i] = 1;
		b.v[1][n + 2] = 0;
		for (int i = 2; i <= n + 1; i++)
			for (int j = i; j <= n + 1; j++)
				b.v[i][j] = 1;
		quickpow(a, b, m);
		printf("%d\n", a.v[1][n + 1]);
	}
}

Yet Another Number Sequence 代码

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace  std;
#pragma warning (disable:4996)
typedef long long LL;
const int maxn = 85;
const LL mod = 1e9 + 7;
LL n; int k;
struct Matrix
{
	LL n, m;
	LL v[maxn][maxn];
	Matrix(int n = 0, int m = 0) :n(n), m(m) {
		memset(v, 0, sizeof(v));
	}
	void clear() {
		memset(v, 0, sizeof(v));
	}
	void show() {
		for (int i = 1; i <= n; i++) {
			for (int j = 1; j <= m; j++)
				cout << v[i][j] << ' ';
			cout << '\n';
		}
	}
	friend Matrix operator *(const Matrix& a, const Matrix& b) {
		Matrix res(a.n, b.m);
		for (int i = 1; i <= a.n; i++)
			for (int j = 1; j <= b.m; j++)
				for (int k = 1; k <= a.m; k++)
					res.v[i][j] = (res.v[i][j] + a.v[i][k] * b.v[k][j] % mod) % mod;
		return res;
	}
};
int comb[41][41];
void Pre_Work() {
	for (int i = 0; i <= 40; i++)
		comb[i][i] = comb[i][0] = 1;
	for (int i = 2; i <= 40; i++) {
		for (int j = 1; j < i; j++)
			comb[i][j] = (LL(comb[i - 1][j]) + comb[i - 1][j - 1]) % mod;
	}
}
Matrix a;
void Matrix_a() {
	a.n = 1; a.m = 2 * k + 3;
	for (int i = 1; i <= k + 1; i++)
		a.v[1][i] = (LL(1) << (i - 1)) % mod;
	for (int i = k + 2; i <= 2 * k + 2; i++)
		a.v[1][i] = (LL(2) << (i - k - 2)) % mod;
	a.v[1][2 * k + 3] = (LL(1) << k + 1) + 1;
	//a.show();
}
Matrix b;
void Matrix_b() {
	b.n = 2 * k + 3;b.m = 2 * k + 3;
	for (int i = 1; i <= k + 1; i++)
		for (int j = 1; j <= i; j++)
			b.v[j + k + 1][i] = comb[i - 1][j - 1];
	for (int i = k + 2; i <= 2 * k + 2; i++) {
		for (int j = 1; j <= i - k - 1; j++) {
			b.v[j][i] = comb[i - k - 2][j - 1];
			b.v[j + k + 1][i] = comb[i - k - 2][j - 1];
		}
	}
	for (int i = 1; i <= k + 1; i++)
		b.v[i][2 * k + 3] = b.v[i + k + 1][2 * k + 3] = comb[k][i - 1];
	b.v[2 * k + 3][2 * k + 3] = 1;
	//b.show();
}
void quickpow(Matrix& res, Matrix m, LL p) {
	while (p) {
		if (p & 1)
			res = res * m;
		m = m * m;
		p >>= 1;
	}
}
int main() {
	scanf("%I64d%d", &n, &k);
	if (n == 1) {
		printf("1\n");
		return 0;
	}
	Pre_Work();
	Matrix_a();
	Matrix_b();
	quickpow(a, b, n - 2);
	printf("%I64d\n", a.v[1][2 * k + 3]);
}

C - Arc of Dream 代码

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
#pragma warning (disable:4996)
typedef long long LL;
const LL mod = 1e9 + 7;
const int maxn = 7;
struct Matrix
{
	LL n, m;
	LL v[maxn][maxn];
	Matrix(int n = 0, int m = 0) :n(n), m(m) {
		memset(v, 0, sizeof(v));
	}
	void clear() {
		memset(v, 0, sizeof(v));
	}
	void show() {
		for (int i = 1; i <= n; i++) {
			for (int j = 1; j <= m; j++)
				cout << v[i][j] << ' ';
			cout << '\n';
		}
	}
	friend Matrix operator *(const Matrix& a, const Matrix& b) {
		Matrix res(a.n, b.m);
		for (int i = 1; i <= a.n; i++)
			for (int j = 1; j <= b.m; j++)
				for (int k = 1; k <= a.m; k++)
					res.v[i][j] = (a.v[i][k] * b.v[k][j] % mod + res.v[i][j])%mod;
		return res;
	}
};
LL a0, ax, ay, b0, bx, by;
Matrix a;
void Matrix_a() {
	a.clear();
	a.n = 1; a.m = 6;
	a.v[1][1] = a0 * b0; a.v[1][1] %= mod;
	a.v[1][2] = a0;
	a.v[1][3] = ay;
	a.v[1][4] = b0;
	a.v[1][5] = by;
	a.v[1][6] = 0;
	//a.show();
}
Matrix b;
void Matrix_b() {
	b.clear();
	b.n = 6; b.m = 6;
	b.v[1][1] = ax * bx; b.v[1][1] %= mod;
	b.v[2][1] = ax * by; b.v[2][1] %= mod;
	b.v[3][1] = by;
	b.v[4][1] = bx * ay; b.v[4][1] %= mod;
	b.v[2][2] = ax;
	b.v[3][2] = 1;
	b.v[3][3] = 1;
	b.v[4][4] = bx;
	b.v[5][4] = 1;
	b.v[5][5] = 1;
	b.v[1][6] = b.v[6][6] = 1;
	//b.show();
}
void quickpow(Matrix& res, Matrix m, LL p) {
	while (p) {
		if (p & 1)
			res = res * m;
		m = m * m;
		p >>= 1;
	}
}
int main() {
	LL n;
	while (~scanf("%lld", &n)) {
		scanf("%lld%lld%lld", &a0, &ax, &ay);
		a0 %= mod; ax %= mod; ay %= mod;
		scanf("%lld%lld%lld", &b0, &bx, &by);
		b0 %= mod; bx %= mod; by %= mod;
		Matrix_a();
		Matrix_b();
		quickpow(a, b, n);
		printf("%lld\n", a.v[1][6]);
	}
}

Bear in the Field 代码

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
#pragma warning (disable:4996)
typedef long long LL;
const int maxn = 7;
LL mod;
struct Matrix
{
	LL n, m;
	LL v[maxn][maxn];
	Matrix(int n = 0, int m = 0) :n(n), m(m) {
		memset(v, 0, sizeof(v));
	}
	void clear() {
		memset(v, 0, sizeof(v));
	}
	void show() {
		for (int i = 1; i <= n; i++) {
			for (int j = 1; j <= m; j++)
				cout << v[i][j] << ' ';
			cout << '\n';
		}
	}
	friend Matrix operator *(const Matrix& a, const Matrix& b) {
		Matrix res(a.n, b.m);
		for (int i = 1; i <= a.n; i++)
			for (int j = 1; j <= b.m; j++)
				for (int k = 1; k <= a.m; k++)
					res.v[i][j] = (a.v[i][k] * b.v[k][j] % mod + res.v[i][j]) % mod;
		return res;
	}
};
LL sx, sy, dx, dy, n;
Matrix a;
void Matrix_a() {
	a.clear();
	a.n = 1; a.m = 6;
	a.v[1][1] = sx;
	a.v[1][2] = sy;
	a.v[1][3] = dx;
	a.v[1][4] = dy;
	a.v[1][5] = 0;
	a.v[1][6] = 1;
	//a.show();
}
Matrix b;
void Matrix_b() {
	b.clear();
	b.n = 6; b.m = 6;
	b.v[1][1] = b.v[6][1] = 2;
	b.v[2][1] = b.v[3][1] = b.v[5][1] = 1;
	b.v[2][2] = b.v[6][2] = 2;
	b.v[1][2] = b.v[4][2] = b.v[5][2] = 1;
	b.v[6][3] = 2;
	b.v[1][3] = b.v[2][3] = b.v[3][3] = b.v[5][3] = 1;
	b.v[6][4] = 2;
	b.v[1][4] = b.v[2][4] = b.v[4][4] = b.v[5][4] = 1;
	b.v[5][5] = b.v[6][5] = 1;
	b.v[6][6] = 1;
	//b.show();
}
void quickpow(Matrix& res, Matrix& m, LL p) {
	while (p) {
		if (p & 1)
			res = res * m;
		m = m * m;
		p >>= 1;
	}
}
int main() {
	scanf("%I64d", &mod);
	scanf("%I64d%I64d%I64d%I64d%I64d", &sx, &sy, &dx, &dy, &n);
	sx--; sy--;
	Matrix_a();
	Matrix_b();
	quickpow(a, b, n);
	a.v[1][1]++; a.v[1][2]++;
	if (a.v[1][1] <= 0)a.v[1][1] += mod;
	if (a.v[1][2] <= 0)a.v[1][2] += mod;
	printf("%I64d %I64d\n", a.v[1][1], a.v[1][2]);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值