1 条题解
-
0
题目解析
这道题的核心在于理解原始输入的结构与拦截后的数据关系。
原输入结构
原始合法输入包含:
- 第一行:两个整数 和 (网格大小)
- 接下来 行:每行 个整数,网格内的数值
因此总共有:
- 个整数( 和 )
- 个整数(网格内的数据)
总整数个数:
问题转化
拦截者将所有这些 个整数打乱顺序,全部放在一行。题目保证 和 本身也在这 个整数之中(即 和 两个值也作为数据出现在输入流中)。
我们已知 和打乱后的整数序列,需要恢复任意一组可能的 。
核心关系
由 可得:
我们需要在打乱后的整数中,找到两个数 和 ,使得:
并且 和 必须在序列中出现至少一次(注意:若 ,需要出现至少两次)。
解法思路
方法一:计数器法
. 统计每个整数 在输入中出现的次数,存入数组
freq[x]。 . 遍历所有可能的 ():- 若 ,检查 (因为 既作为尺寸值出现,又可能在网格内重复出现,但这里至少需要出现两次)
- 否则,若 ,令 ,检查 且 (且 在 范围内)
. 输出找到的第一组 。
时间复杂度:(排序可优化到 ,但这里遍历 + 取模可视为 )。
方法二:双指针法
. 对输入数组排序。 . 使用双指针 , ,寻找两个数 和 满足 。 3. 注意: 和 都可能等于 或 ,双指针遍历自然能处理相等情况。
这种方法不需要额外处理 的边界情况。
代码解析(计数器法)
#include <iostream> #include <vector> using namespace std; int main() { int t; cin >> t; while (t--) { int k; cin >> k; vector<int> freq(k + 1, 0); for (int i = 0; i < k; i++) { int x; cin >> x; freq[x]++; } pair<int, int> solution = {-1, -1}; // 遍历可能的 n for (int i = 1; i <= k; i++) { // 情况1: n == m if (i * i == k - 2) { if (freq[i] > 1) { solution = {i, i}; } } // 情况2: n != m else if ((k - 2) % i == 0) { int j = (k - 2) / i; if (j >= 1 && j <= k && freq[i] > 0 && freq[j] > 0) { solution = {i, j}; } } } cout << solution.first << " " << solution.second << endl; } return 0; }关键细节
- 数组大小设为 是因为输入值 。
- 检查 且 防止越界。
- 如果 ,必须保证 ,因为 和 都需要在序列中出现(至少两个 )。
- 当 时,只需 且 。
复杂度分析
- 时间复杂度: 遍历一次统计频率, 遍历寻找解 → 。
- 空间复杂度: 存储频率数组。
题目提到 是因为排序方法,但这里频率数组法更优。
总结
这道题的本质是已知 和一组包含 和 的数值,求 的任意解。利用频率统计可以高效求解,注意 时的出现次数要求即可。
- 1
信息
- ID
- 6279
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 3
- 标签
- 递交数
- 4
- 已通过
- 1
- 上传者