题解:P13756 【MX-X17-T5】Matrix

咕了半年的题解。

比较简洁的做法。

显然,任何可表示的矩阵 \(A\) 都满足:其每一行与每一列的元素和均为同一个定值 \(S\)。反过来,只要知道 \(A\) 左上角 \((n-1)\times (n-1)\) 的子矩阵以及 \(S\),就可以唯一确定整个矩阵 \(A\)。因此,这类矩阵构成的线性空间维数恰好为 \((n-1)^2+1\)。观察到这恰好等于题目给出的 \(M\) 的上界,因此问题实际上可以转化为,如何恰当地构造出这个矩阵空间的一组基。

一个自然的思路是,在 \(A\) 中选出 \((n-1)^2+1\) 个位置,满足:对于任意一个可表示矩阵 \(B\),如果 \(B\) 在这些位置上的取值都与 \(A\) 相同,那么必有 \(B=A\)。此时,我们只需让基中的每个矩阵对应一个选出的位置,在确定系数时,每个基矩阵负责将自己对应的位置调整到与 \(A\) 相同即可。

考虑如何构造基矩阵,使得我们能较为独立地控制某个位置 \((i,j)\) 上的值。不妨考察一个 \((i,j,n)\) 的置换三元环,也就是令 \(p_i=j,p_j=n,p_n=i\),其他位置上是 \(p_k=k\)。这样构造的主要动机是,我们更加关心左上角 \((n-1)\times (n-1)\) 的子矩阵的取值,可以把第 \(n\) 行和第 \(n\) 列视作一个缓冲区。然而在 \(i=j\) 时上述构造不成立,此时不妨直接考虑置换二元环 \((i,n)\),令 \(p_i=n,p_n=i\),但是这样就控制不了 \((i,i)\) 的取值了。这启发我们这样选位置:取左上角 \((n-1)\times (n-1)\) 的子矩阵中非对角线的位置,再把第 \(n\) 列全部选上。对三类位置分别构造基矩阵:

  • \(1\leq i,j<n\land i\neq j\):取三元环,令 \(p_i=j,p_j=n,p_n=i\)
  • \(1\leq i<n,j=n\):取二元环,令 \(p_i=n,p_n=i\)
  • \(i=j=n\):取单位矩阵。

这样我们就得到了基矩阵的构造。

记控制位置 \((i,j)\) 的基矩阵为 \(B_{i,j}\),我们来证明我们构造的是一组合法的基。

证明

要证明我们构造的基矩阵线性无关,等价于证明 \(\sum c_{i,j}B_{i,j}\) 的唯一解是 \(c_{i,j}\) 都为 \(0\)

还是对三类位置分类讨论:

  • \(1\leq i,j<n\land i\neq j\):只有 \(B_{i,j}\) 能在 \((i,j)\) 处贡献 \(1\),因此 \(c_{i,j}=0\)
  • \(1\leq i<n,j=n\):由于第一类位置的系数恒为 \(0\),只有 \(B_{i,n}\) 能在 \((i,n)\) 处贡献 \(1\),因此 \(c_{i,n}=0\)
  • \(i=j=n\):只有单位矩阵能在 \((n,n)\) 处贡献 \(1\),因此 \(c_{n,n}=0\)

综上,所有 \(c_{i,j}\) 都为 \(0\)\(\Box\)

系数的构造也呼之欲出了:

  • \(i=j=n\)\(c_{n,n}=A_{n,n}\)
  • \(1\leq i,j<n\land i\neq j\)\(c_{i,j}=A_{i,j}\)
  • \(1\leq i<n,j=n\):注意到形如 \((k,i,n)\) 的置换三元环也会对 \((i,n)\) 产生贡献,需要减掉,即 \(c_{i,n}=A_{i,n}-\sum\limits_{k=1}^{n-1}[k\neq i]A_{k,i}\)

直接按照上述过程构造即可。时间复杂度为 \(\mathcal{O}(n^3+qn^2)\)

代码
#include <bits/stdc++.h>

using namespace std;

using ll = long long;
using i128 = __int128;
using ui = unsigned int;
using ull = unsigned long long;
using u128 = unsigned __int128;
using ld = long double;
using pii = pair<int, int>;
const int MAXN = 201;

template<typename T> inline T lowbit(T x) { return x & -x; }
template<typename T> inline void chk_min(T &x, T y) { x = y < x ? y : x; }
template<typename T> inline void chk_max(T &x, T y) { x = x < y ? y : x; }

int n, q, m, p[MAXN], A[MAXN][MAXN];

int main() {
	ios::sync_with_stdio(0), cin.tie(0);
	cin >> n >> q >> m;
	m = (n - 1) * (n - 1) + 1;
	cout << m << '\n';
	iota(p + 1, p + n + 1, 1);
	for (int k = 1; k <= n; ++k) cout << p[k] << " \n"[k == n];
	for (int i = 1; i < n; ++i) for (int j = 1; j < n; ++j) {
		p[i] = j, p[j] = n, p[n] = i;
		for (int k = 1; k <= n; ++k) cout << p[k] << " \n"[k == n];
		p[i] = i, p[j] = j, p[n] = n;
	}
	while (q--) {
		for (int i = 1; i <= n; ++i) for (int j = 1; j <= n; ++j) cin >> A[i][j];
		ll S = accumulate(A[1] + 1, A[1] + n + 1, 0ll);
		bool ok = 1;
		for (int i = 2; i <= n; ++i)
			if (accumulate(A[i] + 1, A[i] + n + 1, 0ll) != S) { ok = 0; break; }
		for (int j = 1; j <= n; ++j) {
			ll sum = 0;
			for (int i = 1; i <= n; ++i) sum += A[i][j];
			if (sum != S) { ok = 0; break; }
		}
		if (!ok) { cout << "0\n"; continue; }
		cout << "1 ";
		cout << A[n][n] << ' ';
		for (int i = 1; i < n; ++i) for (int j = 1; j < n; ++j) {
			if (i != j) cout << A[i][j] << ' ';
			else {
				ll c = A[i][n];
				for (int k = 1; k < n; ++k) if (k != i) c -= A[k][i];
				cout << c << ' ';
			}
		}
		cout << '\n';
	}
	return 0;
}
posted @ 2026-03-23 16:36  P2441M  阅读(5)  评论(0)    收藏  举报