[ARC135D] Add to Square

对网格 \(A\)黑白染色,黑色位置正负取反。这样操作就变为,左上右下加 \(x\),右上左下减 \(x\)


\(sx_i=\sum_{j=1}^m A_{i,j}\)\(sy_j=\sum_{i=1}^n A_{i,j}\)
容易发现,任意行列的和都与 \(A\) 相同的所有矩阵都是可达的。


接下来考虑怎么算出最小的最终矩阵 \(B\)
首先有:答案不小于 \(Sx=\sum_{i=1}^n |sx_i|\),也不小于 \(Sy=\sum_{j=1}^m |sy_j|\)

我们尝试证明答案能取到 \(\max(Sx,Sy)\) 这个下界。
\(sx_i\) 看做需要给行 \(i\) 分配 \(sx_i\) 的总权值,\(sy_j\) 同理。

  • 那么每次如果存在一个 \(sx_i\)\(sy_j\) 同号则在 \(B_{i,j}\) 算上 \(\min(|sx_i|,|sy_j|)\) 的贡献(正负符号取决于 \(sx,sy\))。
  • 如果不存在同号则操作一对 \(sx_{u}>0,sx_{v}<0\) 或一对 \(sy_u>0,sy_u<0\),直至所有 \(sx,sy\) 都为 \(0\)

上述过程可以理解为,操作一对 \(sx_i,sy_j\) 的时候,是给 \(Sx,Sy\) 都减去一个数。而开始操作两行/两列的时候,就等价于 \(Sx,Sy\) 中的一个已经减到 \(0\) 了(因为 \(\sum_{i=1}^n sx_i=\sum_{j=1}^m sy_j\)


点击查看代码
#include <bits/stdc++.h>
#define FL(i, a, b) for (int i = (a); i <= (b); ++i)
#define FR(i, a, b) for (int i = (a); i >= (b); --i)
using namespace std;
typedef long long ll;
const int N = 510;
int n, m;
ll sx[N], sy[N], B[N][N];
bool Work() {
    int px = 0, nx = 0;
    int py = 0, ny = 0;
    FL(i, 1, n) {
        if (sx[i] > 0) px = i;
        if (sx[i] < 0) nx = i;
    }
    FL(i, 1, m) {
        if (sy[i] > 0) py = i;
        if (sy[i] < 0) ny = i;
    }
    if (px && py) {
        ll t = min(sx[px], sy[py]);
        B[px][py] += t;
        sx[px] -= t, sy[py] -= t;
        return 1;
    }
    if (nx && ny) {
        ll t = max(sx[nx], sy[ny]);
        B[nx][ny] += t;
        sx[nx] -= t, sy[ny] -= t;
        return 1;
    }
    if (px && nx) {
        ll t = min(sx[px], -sx[nx]);
        B[px][1] += t, B[nx][1] -= t;
        sx[px] -= t, sx[nx] += t;
        return 1;
    }
    if (py && ny) {
        ll t = min(sy[py], -sy[ny]);
        B[1][py] += t, B[1][ny] -= t;
        sy[py] -= t, sy[ny] += t;
        return 1;
    }
    return 0;
}
int main() {
    scanf("%d %d", &n, &m);
    FL(i, 1, n) {
        FL(j, 1, m) {
            int w;
            scanf("%d", &w);
            if ((i + j) & 1)
                w = -w;
            sx[i] += w;
            sy[j] += w;
        }
    }
    ll Sx = 0, Sy = 0;
    FL(i, 1, n) {
        Sx += abs(sx[i]);
    }
    FL(i, 1, m) {
        Sy += abs(sy[i]);
    }
    while (Work());
    printf("%lld\n", max(Sx, Sy));
    FL(i, 1, n) {
        FL(j, 1, m) {
            if ((i + j) & 1)
                B[i][j] = -B[i][j];
            printf("%lld%c", B[i][j], " \n"[j == m]);
        }
    }
    return 0;
}
posted @ 2026-01-18 10:55  zac2010  阅读(2)  评论(0)    收藏  举报