周黑鸭(a)

题目描述

给两个n×m的矩阵A和B,你可以进行若干次操作。每次操作你可以使A或B的某一行或者某一列的所有元素增加1。
问至少要多少次操作,才能使A和B相等。

输入格式

从文件a.in中读入数据。
第一行一个正整数T,表示数据组数。
每组数据的第一行两个正整数n,m。
接下来n行,每行m个非负整数Ai,j,表示矩阵A。
接下来n行,每行m个非负整数Bi,j,表示矩阵B。

输出格式

输出到文件a.out中。
对于每组数据,输出一行一个整数表示答案。如果无论怎么操作都不能使得A和B相等,输出−1。

解析

用到数学代换比较多,首先B矩阵加相当于A矩阵减,所以我们只关心A矩阵的变化。
设A第i行需要增加ri,第i列需要增加ci,我们的目标是求最小的|ri|+|ci|
r1=x,通过第一行的信息可以得到ci=B1,iA1,ix,通过第一列得到ri=Bi,1Ai,1B1,1+A1,1+x
有一个显然的性质Ai,j+ri+cj=Bi,j,通过此判断无解情况。
最后要求形如i=1n+m|xai|的形式(注意只是形如),那么通过数学可以知道x取a的中位数的答案最小。

代码

#include <bits/stdc++.h>
#define ll long long
#define eb emplace_back
using namespace std;
const int N = 1e5 + 10;
int T, n, m;
ll a[N], b[N];
int id(int x, int y) {return (x - 1) * m + y;}
void solve() {
ll ans = 0;
vector<ll> vec;
cin >> n >> m;
for (int i = 1; i <= n * m; i ++) cin >> a[i];
for (int i = 1; i <= n * m; i ++) {
cin >> b[i]; a[i] = b[i] - a[i];
}
for (int i = 1; i <= n; i ++)
for (int j = 1; j <= m; j ++)
if (a[id(i, j)] != a[id(1, j)] - a[id(1, 1)] + a[id(i, 1)])
//return puts("-1"), void();
{puts("-1"); return ;}
for (int i = 1; i <= n; i ++) vec.eb(a[1] - a[(i - 1) * m + 1]);
for (int i = 1; i <= m; i ++) vec.eb(a[i]);
sort(vec.begin(), vec.end());
ll x = vec[(n + m) / 2];//取中位数
for (auto p : vec) ans += abs(x - p);
printf("%lld\n", ans);
}
int main() {
ios::sync_with_stdio(false);
cin.tie(0); cout.tie(0);
cin >> T;
while (T --) solve();
return 0;
}

image
(额......)



如果您觉得阅读本文对您有帮助,请点一下“推荐”按钮,您的“推荐”将是我最大的写作动力!欢迎各位转载,但是未经作者本人同意,转载文章之后必须在文章页面明显位置给出作者和原文连接,否则保留追究法律责任的权利。
posted @   YHXo  阅读(192)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示