YBTOJ 6.1例4 矩阵求和 题解

暴力怎么写很显然
暴力过不去也很显然

这题的关键在于矩阵套矩阵 那么我们构造一个矩阵 使ta的某一个元素为 \(\sum\limits_{i=1}^kA^i\) 即可

那么我们思考一下怎么构造

首先在此矩阵里构造一个 A 的 x + 1 次项是非常简单的
然后这个时候假如我们的矩阵里还有 \(\sum\limits_{i=1}^xA^i\) 那我们就能转移出下一个矩阵的对应
并且在下一项中应该还有 A 的 x + 2 次项在对应位置
那么我们可以猜这个项是由 A 的 x + 1 次项乘 A 加上一个什么项乘 0 得到的
同理 sum 项由原来的 sum 项乘 I 加上 A 的 x + 1 次项得到的

然后经过一顿数学直觉的猜想 就可以构造出下面这个矩阵:
\(\begin{vmatrix}A&I\\0&I\end{vmatrix}\)
ta正好满足上述的所有性质
答案即为这个矩阵的 k + 1 次方的右上角元素减一个单位矩阵

code:

#include <bits/stdc++.h>
using namespace std;

const int N = 31;
int n, m, k;

struct Matrix {
	int a[N][N];	
};

struct node {
	Matrix a[3][3];
};

void init_Matrix(Matrix &x) {
	for (int i = 1; i <= n; ++i) {
		for (int j = 1; j <= n; ++j) {
			if (i == j) x.a[i][j] = 1;
			else x.a[i][j] = 0;
		}
	}
}

void set_Matrix(Matrix &x) {
	for (int i = 1; i <= n; ++i) {
		for (int j = 1; j <= n; ++j) x.a[i][j] = 0;
	}
}

Matrix operator * (Matrix x, Matrix y) {
	Matrix ret;
	set_Matrix(ret);
	for (int i = 1; i <= n; ++i) {
		for (int j = 1; j <= n; ++j) {
			for (int k = 1; k <= n; ++k) {
				ret.a[i][j] += x.a[i][k] * y.a[k][j];
				ret.a[i][j] %= m;
			}
		}
	}
	return ret;
}

Matrix operator + (Matrix x, Matrix y) {
	for (int i = 1; i <= n; ++i) {
		for (int j = 1; j <= n; ++j) {
			x.a[i][j] = x.a[i][j] + y.a[i][j];
			x.a[i][j] %= m;
		}
	}
	return x;
}

void init_node(node &x) {
	for (int i = 1; i <= 2; ++i) {
		for (int j = 1; j <= 2; ++j) {
			if (i == j) init_Matrix(x.a[i][j]);
			else set_Matrix(x.a[i][j]);
		}
	}
}

void set_node(node &x) {
	for (int i = 1; i <= 2; ++i) {
		for (int j = 1; j <= 2; ++j) set_Matrix(x.a[i][j]);
	}
}

node operator * (node x, node y) {
	node ret;
	set_node(ret);
	for (int i = 1; i <= 2; ++i) {
		for (int j = 1; j <= 2; ++j) {
			for (int k = 1; k <= 2; ++k) {
				Matrix tmp = x.a[i][k] * y.a[k][j];
				ret.a[i][j] = ret.a[i][j] + tmp;
			}
		}
	}
	return ret;
}

void print(node x) {
	for (int i = 1; i <= n; ++i) {
		for (int j = 1; j <= n; ++j) {
			if (i == j) printf("%d ",(x.a[1][2].a[i][j] - 1 + m) % m);  
			else printf("%d ",x.a[1][2].a[i][j]);
		}
		printf("\n");
	}
}

node ksm_node(node x, int k) {
	node ret;
	init_node(ret);
	while (k) {
		if (k & 1) ret = ret * x;
		x = x * x;
		k >>= 1;
	}
	return ret;
}

int main() {
	scanf("%d%d%d", &n, &k, &m);
	node x;
	for (int i = 1; i <= n; ++i) {
		for (int j = 1; j <= n; ++j) scanf("%d", &x.a[1][1].a[i][j]);
	}
	init_Matrix(x.a[1][2]);
	init_Matrix(x.a[2][2]);
	set_Matrix(x.a[2][1]);
	
	x = ksm_node(x, k + 1);
	print(x);
	
	return 0;
}

(关于print函数里那个+m ybt上不加m才能AC 但是实际上你不加m连样例都过不去 std出大锅)

posted @ 2023-05-24 11:30  Steven24  阅读(73)  评论(0)    收藏  举报