语言月赛 202406 数组交换
题目概述¶
- 有一个 $n \times m$ 的二维数组 $a$。
- 有三种操作:
- 交换两行
- 交换两列
- 查询某个元素的值
- 操作执行 $q$ 次后,需要输出所有查询操作的结果和最终数组状态。
关键点与难点¶
- 直接交换行列数组会导致 $O(nm)$ 的代价,执行 $q$ 次操作会非常慢。
- 题目规模最大 $n, m \leq 1000$,$q \leq 10^5$,逐个元素交换不可行。
核心思路:用映射数组模拟行列交换¶
-
维护两个数组:
r
:长度为 $n$,r[i]
表示当前第 $i$ 行实际对应的是原始数据中的哪一行。c
:长度为 $m$,c[j]
表示当前第 $j$ 列实际对应的是原始数据中的哪一列。
-
初始化:
r[i] = i
(表示初始时第 $i$ 行映射到自身)c[j] = j
-
交换行操作(类型1):
- 交换
r[x]
和r[y]
的值
- 交换
-
交换列操作(类型2):
- 交换
c[x]
和c[y]
- 交换
-
查询操作(类型3):
- 查询 $a[r[x], c[y]]$ 即为当前 $a_{x,y}$ 的值。
-
输出最终数组:
- 对所有 $i \in [1, n]$, $j \in [1, m]$ 输出 $a[r[i], c[j]]$
示例代码¶
#include <bits/stdc++.h>
using namespace std;
constexpr int N = 1e3 + 5;
int n, m, q, r[N], c[N];
char a[N][N];
int main()
{
cin >> n >> m >> q;
for (int i = 1; i <= n; i++)
{
r[i] = i;
for (int j = 1; j <= m; j++)
{
c[j] = j;
cin >> a[i][j];
}
}
while (q--)
{
int op, x, y;
cin >> op >> x >> y;
if (op == 1) swap(r[x], r[y]);
if (op == 2) swap(c[x], c[y]);
if (op == 3) cout << a[r[x]][c[y]] << "\n";
}
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= m; j++)
cout << a[r[i]][c[j]];
cout << "\n";
}
return 0;
}
优势分析¶
- 所有行列交换操作都是 $O(1)$ 时间复杂度,只修改映射数组。
- 查询操作也是 $O(1)$,直接用映射数组定位。
- 最后输出数组时,按映射访问即可,无需多次交换。
复杂度¶
时间复杂度:$O(nm + q)$,其中 $nm$ 用于输入和输出,$q$ 用于操作处理。
空间复杂度:$O(nm)$ 用于存储数组,$O(n + m)$ 用于映射数组。