#枚举 ## 思路 首先,由于 $N$ 最大有 $2\times 10^5$,很显然我们不能通过枚举 $(a,b)$ 的方式进行处理,因为这种方式的时间复杂度至少为 $\mathcal O(n^2)$,因此我们需要更换枚举的方式。 对样例进行观察,很显然可以发现满足的数对 $(a,b)$ 当中,$a$ 和 $b$ 在原数组当中对应的位置都是相邻的。例如 $a=1,b=2$ 且满足条件,则可能是这样: ```cpp …… 1 2 …… 1 2 …… ``` 或者 ```cpp …… 2 1 …… 2 1 …… ``` 还可以 ```cpp …… 2 1 …… 1 2 …… ``` 即 $1$ 和 $2$ 都是相邻的。需要注意的是这种不行 ```cpp …… 1 2 2 1 …… ``` 因为不能有相同的元素相邻。 结合上面的结论,我们就可以很简单地优化枚举方式了。由于有两对 $(a,b)$ 在原数组的位置是相邻的,因此我们只需要枚举相邻的元素,然后看一看是否符合条件就行了。我这里使用 vector 存储每个元素的两个位置。时间复杂度 $\mathcal O(n)$。 ## 代码 ```cpp #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; } ```