G - 二回の交換/Exactly Two Adjacent Swaps Editorial
by
cn449
\([X_1, X_2, \ldots, X_K]\) で要素が \(X_1, X_2, \ldots, X_K\) からなる多重集合を表すものとします。
まず、\(A = B\) であるときには \(A_1\) と \(A_2\) の値を入れ替えることを \(2\) 回行えばよいので答えは Yes となります。
以下 \(A \neq B\) とします。\(A_i \neq B_i\) なる最小の \(i\) および \(A_j \neq B_j\) なる最大の \(j\) をとります。
操作を終えた時点で \([A_1, A_2, \ldots, A_i]\) は \([B_1, B_2, \ldots, B_i]\) に一致していなければならないことと \([A_1, A_2, \ldots, A_i]\) を変える可能性のある操作は \(A_i\) と \(A_{i + 1}\) を入れ替えるもののみであるため、\(A_i\) と \(A_{i + 1}\) の値を入れ替える操作が \(1\) 度以上行われたことが必要です。
同様に考えることにより、\(A_{j - 1}\) と \(A_j\) の値を入れ替える操作が行われたことも必要であることがわかります。
\(i = N\) または \(j = 1\) のときは上記のような操作が行えないため答えが No であることに注意してください。
以下 \(i\) と \(j\) の関係によって場合分けを行います。
(1) \(i = j\) のとき
\(k \neq i\) のとき \(A_k = B_k\) であるため、\([A_1, A_2, \ldots, A_N] \neq [B_1, B_2, \ldots, B_N]\) です。したがって、どのように操作を行っても \(A = B\) とならないことがわかります。
(2) \(i + 1 = j\) のとき
\(A_i\) と \(A_{i + 1}\) の値を入れ替える操作と \(A_{j - 1}\) と\(A_j\) の値を入れ替える操作は同じものを意味していることに注意してください。
\(k \neq i, j\) のとき \(A_k = B_k\) であることと \(A_i \neq B_i\)、\(A_j \neq B_j\) であることから \(A_i = B_j\) および \(A_j = B_i\) が成り立っていることが必要です。
上の条件が成り立っていないときは答えが No であるため、以下 \(A_i = B_j\) および \(A_j = B_i\) が成り立っているとします。
\(A_i\) と \(A_{i + 1}\) の値を入れ替える操作が \(1\) 回目の操作であったとき、\(1\) 回目の操作を終えた後に \(A = B\) となります。したがって、\(2\) 回目の操作では \(A\) を変えない操作ができることが必要十分条件であり、これは \(B_k = B_{k + 1}\) なる \(k\) が存在することと同値です。
\(A_i\) と \(A_{i + 1}\) の値を入れ替える操作が \(2\) 回目の操作であったとき、\(1\) 回目の操作を行う前の \(A\) と\(2\) 回目の操作を行う前の \(A\) が一致していること、すなわち \(1\) 回目の操作によって \(A\) が変わらないことが必要十分です。この条件は \(A_k = A_{k + 1}\) なる \(k\) が存在することと同値です。
以上より、このケースでは \(A_k = A_{k + 1}\) または \(B_k = B_{k +1}\) を満たす \(k\) が存在することが必要十分条件となります。
(3) \(i + 2 = j\) のとき
\(A_i\) と \(A_{i+1}\) の値を入れ替える操作と \(A_{j-1}\) と \(A_j\) の値を入れ替える操作を行う必要があります。これらの操作は可換とは限らないため、\(A_i\) と \(A_{i + 1}\) の値を入れ替えた後に \(A_{j-1}\) と \(A_j\) の値を入れ替える操作、およびこの逆の \(2\) 通りの操作を試し \(A = B\) となるか判定すればよいです。
(4) \(i + 3 \leq j\) のとき
\(A_i\) と \(A_{i + 1}\) の値を入れ替える操作と \(A_{j - 1}\) と \({A_j}\) の値を入れ替える操作は可換です。したがって、実際にこの操作を行い \(A = B\) となるか判定すればよいです。なお、このケースは (3) の場合に帰着して操作の順序を \(2\) 通り試してもよいです。
実装例 (解説中の \(i, j\) がコードでは \(x,y\) に対応しています)
#include <bits/stdc++.h>
#define rep(i, n) for (int i = 0; i < (n); i++)
using namespace std;
template<class T> void er(T a) { cout << a << '\n'; exit(0); }
template<class T, class U> inline bool chmax(T& a, const U& b) { if (a < b) { a = b; return true; } return false; }
template<class T, class U> inline bool chmin(T& a, const U& b) { if (a > b) { a = b; return true; } return false; }
int main() {
int n;
cin >> n;
vector<int> a(n), b(n);
rep(i, n) cin >> a[i];
rep(i, n) cin >> b[i];
if (a == b) er("Yes");
int x = n, y = -1;
rep(i, n) {
if (a[i] != b[i]) {
chmin(x, i);
chmax(y, i);
}
}
if (x == n - 1 or y == 0) er("No");
if (x == y) er("No");
else if (x + 1 == y) {
if (a[x] != b[y] or a[y] != b[x]) er("No");
rep(i, n - 1) if (a[i] == a[i + 1]) er("Yes");
rep(i, n - 1) if (b[i] == b[i + 1]) er("Yes");
cout << "No\n";
}
else if (x + 2 == y) {
vector<int> c = a;
swap(a[x], a[x + 1]);
swap(a[y - 1], a[y]);
swap(c[y - 1], c[y]);
swap(c[x], c[x + 1]);
cout << ((a == b or c == b) ? "Yes" : "No") << '\n';
}
else {
swap(a[x], a[x + 1]);
swap(a[y - 1], a[y]);
cout << (a == b ? "Yes" : "No") << '\n';
}
}
posted:
last update: