一道構造題

Problem

給定一個\(n\times m\)的矩陣,每次可以對矩陣做以下操作:

1、給矩陣的一行同時加上一個數\(k\)

2、給矩陣的一列同時加上一個數\(k\)

3、給矩陣的一條對角線同時加上一個數\(k\)。給定\(t\),即\(\forall j-i=t\),滿足的\(a_{i,j}\)即爲一條對角線。

構造一種方案使得矩陣最後全爲0。無解輸出-1。

\(n,m\leq 10^3\)

Solution

這是一道構造題,我們來考查操作下不變的關係。

考查一個\(3\times 3\)的矩陣,可以發現:\(a_{1,1}-a_{2,1}-a_{1,2}+a_{2,3}+a_{3,2}-a_{3,3}\)始終不變!

在三類操作下,變化的值總是能被抵消掉!(將其黑白染色)

所以只要能填好前兩行和前兩列,依據以上等式可以將全部矩陣推導出來。

問題就變成:將前兩行前兩列通過三種操作變成0,判斷剩下位置是否爲0。如果爲0,則肯定無解;反之則有解。

那麼現在如何將前兩行前兩列變成0?這個很簡單,把\(a_{1,1}\)\(a_{2,2}\)變成0後,對於第一行和第一列的數字,利用操作三變成0;對於第二行第二列,利用一二操作,這樣可以不影響到\(a_{1,1}\)\(a_{1,2}\)

#include <bits/stdc++.h>
typedef long long LL;
const int N = 1005;
int n, m, a[N][N];
LL x[N], y[N], z[N*2];
int main() {
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= m; j++)
			scanf("%d", &a[i][j]);
	x[1] = a[2][2]-a[1][1]; z[n] = -a[2][2];
	for (int i = 2; i <= n; i++) z[n-i+1] = -(a[i][1]+x[i]), x[i+1] = -(a[i+1][2]+z[n-i+1]);
	for (int i = 2; i <= m; i++) z[n+i-1] = -(a[1][i]+x[1]+y[i]), y[i+1] = -(a[2][i+1]+z[n+i-1]);
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= m; j++)
			if (a[i][j]+x[i]+y[j]+z[j-i+n]) { puts("-1"); return 0; }
	printf("%d\n", 2*(n+m)-1);
	for (int i = 1; i <= n; i++) printf("1 %d %lld\n", i, x[i]);
	for (int i = 1; i <= m; i++) printf("2 %d %lld\n", i, y[i]);
	for (int i = 1; i <= n+m-1; i++) printf("3 %d %lld\n", i-n, z[i]);
	return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章