P8197

· · 题解

C. 排排队

题意:给定两个长度为 n 的序列 a, b,每次操作只能交换 a 中相邻两个数,求能否在 n^2 次操作内使 a, b 相同,如果可以则构造方案。

**关键词**:构造,选择排序,冒泡排序。 **参考难度**:橙/黄。 **分析**:考虑如果存在一个数 $x$,满足 $x$ 在 $a, b$ 内的出现次数不同,则显然无解。换句话说,如果 $a, b$ 都从小到大排序以后不同,则无解,因此可以先用另一个数组对二者排序,判掉这种情况。 考虑判掉无解以后的情况构造有解的方法:使用类似选择排序的方法,从 1 到 $n$ 枚举 $i$,若 $a_i \neq b_i$,则在 $i$ 后面找到一个 $j$ 满足 $a_j =b_i$,然后交换 $(j, j -1), (j - 1, j - 2), \dots (i + 1, i)$,这样就可以把 $j$ 交换到 $i$。 对于每个 $b_i$ 找到对应的 $j$ 是一个类似选择排序的过程,因此这一步是单次 $O(n)$ 的;将 $j$ 交换到 $i$ 是一个类似冒泡排序的过程,对于每个 $i$,交换的过程也是 $O(n)$。注意这两部分是相互独立的,因此时间复杂度是相加而不是相乘。枚举 $i$ 还有 $O(n)$ 的复杂度,因此总的复杂度是 $O(n^2)$。 考虑交换的次数:显然对于一个 $i$,其交换次数不会超过 $n$,因此总的交换次数不超过 $n^2$。更精细的分析可以发现交换次数的上界是 $\frac{n(n - 1)}{2}$。因为交换是一个类似冒泡排序的过程,因此也可以套用冒泡排序的理论,得到总交换次数不超过 $n^2$ 的结论。 (C++) ```cpp #include <array> #include <iostream> #include <algorithm> const int maxn = 1005; std::array<int, maxn> a, b, c, d; int main() { std::ios::sync_with_stdio(false); std::cin.tie(0); int T, n; for (std::cin >> T; T; --T) { std::cin >> n; a.fill(0); b.fill(0); for (int i = 1; i <= n; ++i) std::cin >> a[i]; for (int i = 1; i <= n; ++i) std::cin >> b[i]; c = a; d = b; std::sort(c.begin(), c.end()); std::sort(d.begin(), d.end()); if (c != d) { std::cout << "NO\n"; } else { std::cout << "YES\n"; for (int i = 1; i <= n; ++i) if (a[i] != b[i]) { for (int j = i; j <= n; ++j) if (a[j] == b[i]) { for (int k = j; k > i; --k) { std::swap(a[k], a[k - 1]); std::cout << k << ' ' << k - 1 << '\n'; } break; } } std::cout << "0 0\n"; } } } ``` (java) ```java import java.util.Scanner; import java.util.Arrays; import java.io.PrintWriter; public class Main { public static void main(String[] args) { Scanner cin = new Scanner(System.in); PrintWriter out = new PrintWriter(System.out); for (int T = cin.nextInt(); T != 0; --T) { int n = cin.nextInt(); int[] a = new int[n], b = new int[n], c = new int[n], d = new int[n]; for (int i = 0; i < n; ++i) { c[i] = a[i] = cin.nextInt(); } for (int i = 0; i < n; ++i) { d[i] = b[i] = cin.nextInt(); } Arrays.sort(c); Arrays.sort(d); boolean flag = true; for (int i = 0; i < n; ++i) if (c[i] != d[i]) { flag = false; break; } if (flag == false) { out.println("NO"); } else { out.println("YES"); for (int i = 0; i < n; ++i) if (a[i] != b[i]) { for (int j = i + 1; j < n; ++j) if (a[j] == b[i]) { for (int k = j; k > i; --k) { out.println((k + 1)+ " " + k); int t = a[k]; a[k] = a[k - 1]; a[k - 1] = t; } break; } } out.println(0 + " " + 0); } } out.flush(); } } ``` (Python) ```python T = int(input()) for t in range(T): n = int(input()) a = list(map(int, input().split())) b = list(map(int, input().split())) c, d = list(), list() for i in a: c.append(i) for i in b: d.append(i) c.sort() d.sort() if c != d: print("NO") else: print('YES') for i in range(0, n): if a[i] != b[i]: for j in range(i, n): if (a[j] == b[i]): k = j while (k != i): print(k, k + 1) a[k], a[k - 1] = a[k - 1], a[k] k -= 1 break print(0, 0) ```