Week14 作业 D - Q老师染砖 POJ - 3734

写在前面:

  • 上一次我们了解了矩阵快速幂,那么矩阵快速幂的应用场景有哪些?

  • 最直接的应用,毫无疑问,只要有线性递推式,就可以使用矩阵快速幂优化计算

  • DP中的状态转移方程很多都是线性递推,我们可以用矩阵快速幂优化DP

题目描述:

衣食无忧的 Q老师 有一天突发奇想,想要去感受一下劳动人民的艰苦生活。

具体工作是这样的,有 N 块砖排成一排染色,每一块砖需要涂上红、蓝、绿、黄这 4 种颜色中的其中 1 种。且当这 N 块砖中红色和绿色的块数均为偶数时,染色效果最佳。

为了使工作效率更高,Q老师 想要知道一共有多少种方案可以使染色效果最佳,你能帮帮他吗?

思路:

定义状态:考虑用A[i] 表示 i 个格子,红绿均为偶数的染色方案数;B[i] 表示 i 个格子,红绿均为奇数的染色方案数;C[i] 表示 i 个格子,红绿有一个为偶数的染色方案数(其实A[i] B[i] C[i]就是F[i][0],F[i][1],F[i][2],不过是换了个名字)

状态转移:A[i] = 2 * A[i-1] + C[i-1] ;B[i] = 2 * B[i-1] + C[i-1] ;C[i] = 2 * A[i-1] + 2 * B[i-1] + 2 * C[i-1] ,其中每一个状态转移都能用矩阵运算优化

边界条件:A[0]=1(红绿都是0个,0是偶数);B[0]=C[0]=0

代码:

采用了静态建立矩阵的方式,使用了memcpy,代码比较简洁,可作为模板

#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;
long long K, MOD=10007;
const int N = 3;
struct Matrix
{
	long long x[N + 1][N + 1];
	Matrix operator*(const Matrix& y) const
	{
		Matrix ret;  //ret==return
		for (int i = 1; i <= N; ++i)
			for (int j = 1; j <= N; ++j)
			{
				ret.x[i][j] = 0;
				for (int k = 1; k <= N; ++k)
					ret.x[i][j] = (ret.x[i][j] + (x[i][k] % MOD) * (y.x[k][j] % MOD) % MOD) % MOD;

			}
		return ret;
	}
	Matrix() { memset(x, 0, sizeof(x)); }
	Matrix(const Matrix& t) { memcpy(x, t.x, sizeof(x)); }
};
Matrix mqpow(Matrix a, int x)
{
	Matrix ret;
	//置为单位矩阵
	for (int i = 1; i <= N; i++)
		ret.x[i][i] = 1;
	//迭代矩阵快速幂
	while (x)
	{
		if (x & 1) ret = ret * a;
		a = a * a;
		x >>= 1;
	}
	return ret;
}
int main()
{
	int T; cin >> T;
	while (T--)
	{
		long long M;
		cin >> M;
		Matrix A;
		A.x[1][1] = 2; A.x[1][2] = 0; A.x[1][3] = 1;
		A.x[2][1] = 0; A.x[2][2] = 2; A.x[2][3] = 1;
		A.x[3][1] = 2; A.x[3][2] = 2; A.x[3][3] = 2;
		Matrix halfAns = mqpow(A, M);
		cout << halfAns.x[1][1] << endl;
	}
	return 0;
}
posted @ 2020-06-12 23:47  菜鸡今天学习了吗  阅读(139)  评论(0编辑  收藏  举报