📅  最后修改于: 2023-12-03 15:28:47.700000             🧑  作者: Mango
给定一个 $n \times m$ 的矩阵 $a_{i, j}$,你需要求出所有左右相邻元素相等的 $4$ 元组 $(i, j, i^\prime, j^\prime)$ 的个数,即满足 $a_{i, j} = a_{i, j+1}, a_{i, j} = a_{i^\prime, j^\prime}, a_{i^\prime, j^\prime} = a_{i^\prime, j^\prime+1}$ 且 $j < j^\prime$ 的 $(i, j, i^\prime, j^\prime)$ 的数量。
$$1 \leq n,m \leq 1000$$
这是一道比较经典的矩阵问题,可以使用枚举和哈希表来解决。
枚举所有可能的 $4$ 元组 $(i, j, i^\prime, j^\prime)$,判断其是否满足题目条件。
而判断条件中包含元素相等,我们可以使用哈希表来判断。
具体来说,哈希表中的 key 为矩阵中出现过的元素值,value 为所有出现该元素值的位置。
然后遍历所有 $4$ 元组 $(i, j, i^\prime, j^\prime)$,判断 $a_{i, j} = a_{i, j+1}$ 和 $a_{i^\prime, j^\prime} = a_{i^\prime, j^\prime+1}$ 是否成立,并从哈希表中查询是否有 $a_{i, j}$ 和 $a_{i^\prime, j^\prime}$ 的索引值在 $j+1$ 和 $j^\prime$ 之间,并统计满足条件的 $4$ 元组数量即可。
这样做的时间复杂度为 $O(nm^2+C)$,其中 $C$ 为哈希表操作的次数。由于 $C$ 的大小与矩阵中元素有关,故该方法可能存在一定的数据敏感性。
下面是基于哈希表的实现,使用 C++ 编写:
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e3+5;
int n, m, a[MAXN][MAXN];
unordered_map<int, vector<int>> mp;
int main() {
cin >> n >> m;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
cin >> a[i][j];
mp[a[i][j]].push_back((i-1)*m+j); // 标记相同元素的位置索引
}
}
int ans = 0;
for (int j = 1; j <= m-1; j++) { // 枚举所有可能的 4 元组
for (int i = 1; i <= n; i++) {
if (a[i][j] == a[i][j+1]) {
int x = a[i][j]; // 取出相同元素值
int l = lower_bound(mp[x].begin(), mp[x].end(), (i-1)*m+j+1) - mp[x].begin(); // 查询左边相邻元素位置的索引
int r = upper_bound(mp[x].begin(), mp[x].end(), (i-1)*m+j+1) - mp[x].begin() - 1; // 查询右边相邻元素位置的索引
for (int k = l; k <= r; k++) {
int x1 = (mp[x][k]-1) / m + 1, y1 = (mp[x][k]-1) % m + 1, y2 = j+1; // 将位置索引转换为坐标
if (x1 > i) ans++; // 判断位置在右下方的 4 元组是否满足条件
}
}
}
}
cout << ans << endl;
return 0;
}
该代码片段返回的 markdown 内容为:
# '门|门 CS 1997 |第 72 题'题解
## 题目描述
给定一个 $n \times m$ 的矩阵 $a_{i, j}$,你需要求出所有左右相邻元素相等的 $4$ 元组 $(i, j, i^\prime, j^\prime)$ 的个数,即满足 $a_{i, j} = a_{i, j+1}, a_{i, j} = a_{i^\prime, j^\prime}, a_{i^\prime, j^\prime} = a_{i^\prime, j^\prime+1}$ 且 $j < j^\prime$ 的 $(i, j, i^\prime, j^\prime)$ 的数量。
$$1 \leq n,m \leq 1000$$
## 思路
这是一道比较经典的矩阵问题,可以使用枚举和哈希表来解决。
枚举所有可能的 $4$ 元组 $(i, j, i^\prime, j^\prime)$,判断其是否满足题目条件。
而判断条件中包含元素相等,我们可以使用哈希表来判断。
具体来说,哈希表中的 key 为矩阵中出现过的元素值,value 为所有出现该元素值的位置。
然后遍历所有 $4$ 元组 $(i, j, i^\prime, j^\prime)$,判断 $a_{i, j} = a_{i, j+1}$ 和 $a_{i^\prime, j^\prime} = a_{i^\prime, j^\prime+1}$ 是否成立,并从哈希表中查询是否有 $a_{i, j}$ 和 $a_{i^\prime, j^\prime}$ 的索引值在 $j+1$ 和 $j^\prime$ 之间,并统计满足条件的 $4$ 元组数量即可。
这样做的时间复杂度为 $O(nm^2+C)$,其中 $C$ 为哈希表操作的次数。由于 $C$ 的大小与矩阵中元素有关,故该方法可能存在一定的数据敏感性。
## 代码
下面是基于哈希表的实现,使用 C++ 编写:
```cpp
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1e3+5;
int n, m, a[MAXN][MAXN];
unordered_map<int, vector<int>> mp;
int main() {
cin >> n >> m;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
cin >> a[i][j];
mp[a[i][j]].push_back((i-1)*m+j); // 标记相同元素的位置索引
}
}
int ans = 0;
for (int j = 1; j <= m-1; j++) { // 枚举所有可能的 4 元组
for (int i = 1; i <= n; i++) {
if (a[i][j] == a[i][j+1]) {
int x = a[i][j]; // 取出相同元素值
int l = lower_bound(mp[x].begin(), mp[x].end(), (i-1)*m+j+1) - mp[x].begin(); // 查询左边相邻元素位置的索引
int r = upper_bound(mp[x].begin(), mp[x].end(), (i-1)*m+j+1) - mp[x].begin() - 1; // 查询右边相邻元素位置的索引
for (int k = l; k <= r; k++) {
int x1 = (mp[x][k]-1) / m + 1, y1 = (mp[x][k]-1) % m + 1, y2 = j+1; // 将位置索引转换为坐标
if (x1 > i) ans++; // 判断位置在右下方的 4 元组是否满足条件
}
}
}
}
cout << ans << endl;
return 0;
}
该代码片段中涉及到的技巧有: