• 一道构造题


    Problem

    给定一个(n imes m)的矩阵,每次可以对矩阵做以下操作:

    1、给矩阵的一行同时加上一个数(k)

    2、给矩阵的一列同时加上一个数(k)

    3、给矩阵的一条对角线同时加上一个数(k)。给定(t),即(forall j-i=t),满足的(a_{i,j})即为一条对角线。

    构造一种方案使得矩阵最后全为0。无解输出-1。

    (n,mleq 10^3)

    Solution

    这是一道构造题,我们来考查操作下不变的关系。

    考查一个(3 imes 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
    ", 2*(n+m)-1);
    	for (int i = 1; i <= n; i++) printf("1 %d %lld
    ", i, x[i]);
    	for (int i = 1; i <= m; i++) printf("2 %d %lld
    ", i, y[i]);
    	for (int i = 1; i <= n+m-1; i++) printf("3 %d %lld
    ", i-n, z[i]);
    	return 0;
    }
    
  • 相关阅读:
    JeePlus:代码生成器
    JeePlus:API工具
    Java实现 洛谷 P1023 税收与补贴问题
    Java实现 洛谷 P1023 税收与补贴问题
    Java实现 洛谷 P1023 税收与补贴问题
    Java实现 洛谷 P1328 生活大爆炸版石头剪刀布
    Java实现 洛谷 P1328 生活大爆炸版石头剪刀布
    Java实现 洛谷 P1328 生活大爆炸版石头剪刀布
    Java实现 洛谷 P1328 生活大爆炸版石头剪刀布
    Java实现 洛谷 P1328 生活大爆炸版石头剪刀布
  • 原文地址:https://www.cnblogs.com/ac-evil/p/14015394.html
Copyright © 2020-2023  润新知