codeforces 955 div 2 D
题目链接 D. Beauty of the mountains
题目大意
解题思路
首先记录所有雪山和没有雪山两种山峰的高度差为 \(tot\) ,然后对于每个可能的子矩,我们可以每次给所有山峰都加一或者减一,因此只要计算出矩阵内两种山峰的个数差的绝对值我们就能得到每次操作该子矩阵对tot的贡献 \(z_{i}\) ,因此我们只需要判断这些子矩阵的贡献值通过加减能否等于 \(tot\) 即可。
故原命题转化为求下面这个式子是否存在整数解, 即 \(d_{i}\) 全为整数,其中 \(d_{i}\) 是每个子矩阵的操作次数,
\[z_{1} \cdot d_{1} + z_{2} \cdot d_{2} + \dots + z_{q} \cdot d_{q} = tot
\]
对于子矩阵的贡献采用二维前缀和即可求出
对于上面式子整数解的存在性问题只需要验证
\[tot \bmod gcd(z_{1}, z_{2}, \dots, z_{q}) = 0
\]
代码
#include <bits/stdc++.h>
#define debug cout << "debug" << endl;
#define debug1(a) cout << #a << " = " << a << endl;
#define debug2(a, b) \
cout << #a << " = " << a << " " << #b << " = " << b << endl;
#define debug3(a, b, c) \
cout << #a << " = " << a << " " << #b << " = " << b << " " << #c << " = " \
<< c << endl;
#define debug4(a, b, c, d) \
cout << #a << " = " << a << " " << #b << " = " << b << " " << #c << " = " \
<< c << " " << #d << " = " << d << endl;
#define debug5(a, b, c, d, e) \
cout << #a << " = " << a << " " << #b << " = " << b << " " << #c << " = " \
<< c << " " << #d << " = " << d << " " << #e << " = " << e << endl;
#define caseT \
int T; \
cin >> T; \
while (T--)
// #define M(x, y) make_pair(x, y)
// #define M(x, y, z) make_tuple(x, y, z)
// #define int long long
// #define int __int128
using namespace std;
// using str = string;
using ull = unsigned long long;
using ll = long long;
// using pii = pair<int, int>;
// using tiii = tuple<int, int, int>;
const int N = 5e2 + 10;
void solve() {
int n, m, k;
cin >> n >> m >> k;
vector<vector<int>> g(n+1, vector<int>(m+1)), sa(n+1, vector<int>(m+1)), sb(n+1, vector<int>(m+1));
vector<int> z;
ll tot = 0;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
cin >> g[i][j];
}
}
//计算二维前缀和
for (int i = 0; i < n; i++) {
string s;
cin >> s;
for (int j = 0; j < (int)s.size(); j++) {
sa[i + 1][j + 1] = sa[i + 1][j] + sa[i][j + 1] - sa[i][j];
sb[i + 1][j + 1] = sb[i + 1][j] + sb[i][j + 1] - sb[i][j];
if (s[j] == '0') {
sa[i + 1][j + 1] += 1;
tot += g[i + 1][j + 1];
} else {
sb[i + 1][j + 1] += 1;
tot -= g[i + 1][j + 1];
}
}
}
tot = abs(tot);
// 计算子矩阵的贡献存起来
for (int i = k; i <= n; i++) {
for (int j = k; j <= m; j++) {
int numa = sa[i][j] - sa[i][j - k] - sa[i - k][j] + sa[i - k][j - k];
int numb = sb[i][j] - sb[i][j - k] - sb[i - k][j] + sb[i - k][j - k];
int num = abs(numa - numb);
if (num) {
z.emplace_back(num);
}
}
}
// 求解所有z的最大公因数
int gc = 0;
for (int i = 0; i < (int)z.size(); i++) {
gc = __gcd(gc, z[i]);
}
// 特判tot==0,和gc==0
if (tot == 0) {
cout << "YES" << "\n";
} else if (gc != 0 && tot % gc == 0) {
cout << "YES" << "\n";
} else {
cout << "NO" << "\n";
}
return;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
caseT
solve();
return 0;
}