思路
首先,由于 最大有 ,很显然我们不能通过枚举 的方式进行处理,因为这种方式的时间复杂度至少为 ,因此我们需要更换枚举的方式。
对样例进行观察,很显然可以发现满足的数对 当中, 和 在原数组当中对应的位置都是相邻的。例如 且满足条件,则可能是这样:
…… 1 2 …… 1 2 ……或者
…… 2 1 …… 2 1 ……还可以
…… 2 1 …… 1 2 ……即 和 都是相邻的。需要注意的是这种不行
…… 1 2 2 1 ……因为不能有相同的元素相邻。
结合上面的结论,我们就可以很简单地优化枚举方式了。由于有两对 在原数组的位置是相邻的,因此我们只需要枚举相邻的元素,然后看一看是否符合条件就行了。我这里使用 vector 存储每个元素的两个位置。时间复杂度 。
代码
#include <iostream>
#include <vector>
using namespace std;
const int kMaxN = 1e6 + 5;
int a[kMaxN], t, n, ans;
vector<int> v[kMaxN];
int main() {
cin.tie(0)->sync_with_stdio(0);
for (cin >> t; t; t--) {
// 读入和初始化
cin >> n;
fill(v + 1, v + n + 1, vector<int>());
ans = 0;
for (int i = 1; i <= 2 * n; i++) {
cin >> a[i];
v[a[i]].push_back(i);
}
// 处理
for (int i = 1; i < 2 * n; i++) {
if (a[i] != a[i + 1] &&
abs(v[a[i]][0] - v[a[i]][1]) != 1 &&
abs(v[a[i + 1]][0] - v[a[i + 1]][1]) != 1) { // 要求相同的数不相邻,不相同的数相邻
int x, y; // 另外两个 (a,b) 的位置
if (i == v[a[i]][0]) {
x = v[a[i]][1];
} else {
x = v[a[i]][0];
}
if (i + 1 == v[a[i + 1]][0]) {
y = v[a[i + 1]][1];
} else {
y = v[a[i + 1]][0];
}
if (abs(x - y) == 1) { // 另外的也要相邻
ans++;
}
}
}
cout << ans / 2 << '\n'; // 注意除以 2,因为这里一个 (a,b) 会枚举两次
}
return 0;
}