1 条题解
-
0
题意简述
有一个 的网格,开始时所有格子都是“未重建”状态。
政府可以先手动重建一些格子。之后,如果一个格子满足:
- 它在上下相邻格子中,至少有一个已经重建;
- 它在左右相邻格子中,至少有一个已经重建;
那么这个格子也能被“带动重建”。
要求最少手动重建多少个格子,才能最终让整个矩阵全部重建。
核心观察
我们考虑这样两个集合:
- 当前哪些行里至少有一个已经重建的格子;
- 当前哪些列里至少有一个已经重建的格子。
关键结论是:
无论进行多少次“相邻援助”,这两个集合都不会发生变化。
为什么?
设某个新格子 被重建了,那么根据题意:
- 它所在列 中,必须原本就有一个上下相邻的已重建格子;
- 它所在行 中,必须原本就有一个左右相邻的已重建格子。
也就是说:
- 第 行早就已经出现在“有重建格子”的行集合里;
- 第 列早就已经出现在“有重建格子”的列集合里。
所以,新重建一个格子,不会让“出现过重建格子的行或列”新增。
这就是本题最重要的不变量。
下界分析
如果最后整个矩阵都要被重建,那么显然:
- 每一行最后都必须出现重建格子;
- 每一列最后都必须出现重建格子。
而由于上面说的那个不变量,这意味着:
在最开始手动选择的那些格子中,就必须已经覆盖所有行和所有列。
于是答案至少满足:
因为:
- 想覆盖全部 行,至少要让这 行都出现;
- 想覆盖全部 列,至少要让这 列都出现。
一个格子只能同时属于 行和 列,所以最少不可能小于 。
构造达到下界
接下来证明这个下界是可以达到的。
不妨设:
那么我们这样构造初始手动重建的格子:
$$(1,1),(2,2),(3,3),\dots,(n,n),(n,n+1),(n,n+2),\dots,(n,m) $$也就是:
- 先选主对角线上的 个格子;
- 再把第 行从第 列到第 列全部选上。
总共选了:
个格子,也就是:
为什么这个构造可行
我们来说明,按上面的方式选点后,整个矩阵最终都能被重建。
对于任意一个格子 :
当 时
- 第 行中有格子 已经被手动重建;
- 第 列中有格子 已经被手动重建。
所以这个格子所在的行、列都已经“连通到重建区域”,之后可以逐步传播出来。
当 时
- 第 行中依然有 ;
- 第 列中有 ,因为第 行后半段全被我们选了。
所以这种格子同样也能被逐步带动重建。
因此整个矩阵最终都能被完全重建。
于是:
结合前面的下界:
可得最终答案就是:
结论
每组测试数据直接输出:
代码实现
#include <bits/stdc++.h> using namespace std; void solve() { int n, m; cin >> n >> m; cout << max(n, m) << '\n'; } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int t; cin >> t; while (t--) solve(); return 0; }复杂度分析
每组测试数据只做一次比较,因此:
总空间复杂度也是:
- 1
信息
- ID
- 6387
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 5
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者