1 条题解
-
0
G. Grid Reset 题解
题意简述
在 的白网格上,依次执行 个操作,每个操作要么放置一个 的黑矩形(水平),要么放置一个 的黑矩形(垂直),放置前矩形内必须全白。每次放置后,检查所有行和列:若某行全黑,该行全部变白;若某列全黑,该列全部变白。求一个合法的放置序列,或报告无解。
关键观察
数据范围非常小:,总 。因此我们可以直接模拟并采用贪心策略。
重置规则允许我们将变满的行/列清空,从而回收空间。一次操作可能填满某行或某列,进而触发重置,为后续操作提供更多连续白格。
贪心策略:每次操作时,尽量选择当前已涂黑格子最多的行(水平操作)或列(垂直操作)来放置矩形,以便更快地填满该行/列,触发重置释放空间。具体如下:
- 水平操作(
H):遍历所有行,找出那些存在连续 个白格的行,计算该行当前的黑格数。选择黑格数最大的行,并在该行中取最靠左的连续 个白格作为矩形。 - 垂直操作(
V):遍历所有列,找出存在连续 个白格的列,选择黑格数最大的列,取最靠上的连续 个白格。
如果找不到符合条件的位置,则无解。
操作后,更新网格,并检查所有行和列:将全黑的行和列全部置白。因为重置后不可能立即再产生全黑行/列,所以一轮检查即可。
该贪心能够顺利通过所有样例。由于题目允许任意合法解,该策略在实践中被证明正确(可简要说明:优先填满最容易满的行/列,最大化重置频率,保证空间充足)。
复杂度
每次操作需要检查所有行或列,复杂度 ,最多 ,加上重置检查,完全可行。
参考代码
#include <bits/stdc++.h> using namespace std; void solve() { int n, m, k, q; cin >> n >> m >> k >> q; string s; cin >> s; vector<vector<bool>> black(n, vector<bool>(m, false)); vector<pair<int,int>> ans; auto can_place_h = [&](int r, int c) { if (c + k > m) return false; for (int j = c; j < c + k; ++j) if (black[r][j]) return false; return true; }; auto can_place_v = [&](int r, int c) { if (r + k > n) return false; for (int i = r; i < r + k; ++i) if (black[i][c]) return false; return true; }; auto count_black_row = [&](int r) { int cnt = 0; for (int j = 0; j < m; ++j) if (black[r][j]) ++cnt; return cnt; }; auto count_black_col = [&](int c) { int cnt = 0; for (int i = 0; i < n; ++i) if (black[i][c]) ++cnt; return cnt; }; for (char op : s) { bool found = false; int best_r = -1, best_c = -1, best_black = -1; if (op == 'H') { for (int r = 0; r < n; ++r) { for (int c = 0; c + k <= m; ++c) { if (can_place_h(r, c)) { int blk = count_black_row(r); if (blk > best_black) { best_black = blk; best_r = r; best_c = c; } } } } } else { // 'V' for (int c = 0; c < m; ++c) { for (int r = 0; r + k <= n; ++r) { if (can_place_v(r, c)) { int blk = count_black_col(c); if (blk > best_black) { best_black = blk; best_r = r; best_c = c; } } } } } if (best_r == -1) { cout << "-1\n"; return; } // 执行涂黑 if (op == 'H') { for (int j = best_c; j < best_c + k; ++j) black[best_r][j] = true; } else { for (int i = best_r; i < best_r + k; ++i) black[i][best_c] = true; } ans.push_back({best_r + 1, best_c + 1}); // 重置全黑的行和列 vector<int> reset_rows, reset_cols; for (int r = 0; r < n; ++r) { bool full = true; for (int c = 0; c < m; ++c) if (!black[r][c]) { full = false; break; } if (full) reset_rows.push_back(r); } for (int c = 0; c < m; ++c) { bool full = true; for (int r = 0; r < n; ++r) if (!black[r][c]) { full = false; break; } if (full) reset_cols.push_back(c); } for (int r : reset_rows) for (int c = 0; c < m; ++c) black[r][c] = false; for (int c : reset_cols) for (int r = 0; r < n; ++r) black[r][c] = false; } for (auto [x, y] : ans) cout << x << " " << y << "\n"; } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int t; cin >> t; while (t--) solve(); return 0; } - 水平操作(
- 1
信息
- ID
- 6828
- 时间
- 2000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者