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;
}