CF1698F Equal Reversal 题解

Description

有一个长度为 nn 的数组 aa。你可以对其进行如下操作:

  • 选择两个下标 llrr,满足 1lrn1 \le l \le r \le nal=ara_l = a_r。然后,将第 ll 个到第 rr 个元素的子段翻转,即将 [al,al+1,,ar1,ar][a_l, a_{l + 1}, \ldots, a_{r - 1}, a_r] 变为 [ar,ar1,,al+1,al][a_r, a_{r-1}, \ldots, a_{l+1}, a_l]

你还给定了另一个长度为 nn 的数组 bb,它是 aa 的一个排列。请找出一组不超过 n2n^2 次操作的方案,将数组 aa 变为 bb,或者报告不存在这样的操作序列。

n500n\leq 500

Solution

注意到一次翻转操作是不会改变 {{ai,ai+1}}\left\{\{a_i,a_{i+1}\}\right\} 的,同时 a1a_1ana_n 也不会改变。所以猜测无解的充要条件是 {{ai,ai+1}}={{bi,bi+1}},a1=b1,an=bn\left\{\{a_i,a_{i+1}\}\right\}=\left\{\{b_i,b_{i+1}\}\right\},a_1=b_1,a_n=b_n

构造就考虑从前往后依次让 ai=bia_i=b_i,满足了 ai=bia_i=b_i 后就把 ai1a_{i-1} 删掉,根据判定条件这个是不会改变正确性的。

假设现在第一个 aibia_i\neq b_i 的下标是 kk,我们设 ak1=x,ak=y,bk=za_{k-1}=x,a_k=y,b_k=z。那么 a[i1,n]=x,y,a_{[i-1,n]}=x,y,\ldotsb[i1,n]=x,z,b_{[i-1,n]}=x,z,\ldots

根据第一个条件,[i1,n][i-1,n] 中一定存在一个下标 jj 满足 {aj,aj+1}={x,z}\{a_j,a_{j+1}\}=\{x,z\},把这个 jj 拿出来。

如果 aj=za_j=zaj+1=xa_{j+1}=x,则直接翻转 [i1,j+1][i-1,j+1] 即可。

如果 aj=xa_j=xaj+1=za_{j+1}=z,则需要用一次操作让 aja_jaj+1a_{j+1} 交换顺序。我们断言当前状态一定存在一个 (l,r)(l,r),使得 al=ara_l=a_rlj<j+1rl\leq j<j+1\leq r

证明就考虑如果不存在这样的数对,那么 a[i1,j]a_{[i-1,j]}a[j+1,n]a_{[j+1,n]} 的颜色种类一定不交。又根据第一个充要条件,{bi,bi+1}\{b_i,b_{i+1}\} 出现在 a[i1,n]a_{[i-1,n]} 中,由于 bi=z=aj+1b_i=z=a_{j+1}{bi1,bi}\{b_{i-1},b_i\} 已经把 {aj,aj+1}\{a_j,a_{j+1}\} 抵消掉了,所以 bi+1b_{i+1} 一定在 a[j+1,n]a_{[j+1,n]} 范围内。依次类推,bi+2,bi+3,,bnb_{i+2},b_{i+3},\ldots,b_n 都在 [j+1,n][j+1,n] 中,这说明 a[j,n]a_{[j,n]} 构成的数对 把 b_{[i-1,n] 的给抵消了,显然不可能。

暴力找到这样的区间后翻转即可。

总次数是 2n2n

时间复杂度:O(n2)O(n^2)

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
#include <bits/stdc++.h>

// #define int int64_t

const int kMaxN = 505;

int n;
int a[kMaxN], b[kMaxN], cnta[kMaxN][kMaxN], cntb[kMaxN][kMaxN];
std::vector<std::pair<int, int>> vec;

void work(int l, int r) {
assert(a[l] == a[r]);
vec.emplace_back(l, r);
std::reverse(a + l, a + 1 + r);
}

void dickdreamer() {
std::cin >> n;
for (int i = 1; i <= n; ++i)
for (int j = 1; j <= n; ++j)
cnta[i][j] = cntb[i][j] = 0;
for (int i = 1; i <= n; ++i) {
std::cin >> a[i];
if (i > 1) ++cnta[std::min(a[i - 1], a[i])][std::max(a[i - 1], a[i])];
}
for (int i = 1; i <= n; ++i) {
std::cin >> b[i];
if (i > 1) ++cntb[std::min(b[i - 1], b[i])][std::max(b[i - 1], b[i])];
}
for (int i = 1; i <= n; ++i)
for (int j = i; j <= n; ++j)
if (cnta[i][j] != cntb[i][j])
return void(std::cout << "NO\n");
if (a[1] != b[1] || a[n] != b[n]) return void(std::cout << "NO\n");
vec.clear();
for (int i = 1; i <= n;) {
for (; i <= n && a[i] == b[i]; ++i) {}
if (i >= n) break;
int p1 = 0, p2 = 0;
for (int j = i; j < n; ++j) {
if (!p1 && a[j] == b[i - 1] && a[j + 1] == b[i]) p1 = j;
if (!p2 && a[j] == b[i] && a[j + 1] == b[i - 1]) p2 = j;
}
assert(p1 || p2);
// for (int j = 1; j <= n; ++j) std::cerr << a[j] << " \n"[j == n];
// 3 3 3 3 3 4 1 3 3
// 3 3 3 3 4 1 3 3 3
if (p2) {
work(i - 1, p2 + 1);
} else {
static int lst[kMaxN];
std::fill_n(lst + 1, n, 0);
int l = 0, r = 0;
for (int j = n; j >= i - 1; --j) {
if (j <= p1 && lst[a[j]] >= p1 + 1) {
l = j, r = lst[a[j]];
break;
}
lst[a[j]] = j;
}
assert(l && r);
work(l, r);
}
}
std::cout << "YES\n" << vec.size() << '\n';
for (auto [l, r] : vec) std::cout << l << ' ' << r << '\n';
}

int32_t main() {
#ifdef ORZXKR
freopen("in.txt", "r", stdin);
freopen("out.txt", "w", stdout);
#endif
std::ios::sync_with_stdio(0), std::cin.tie(0), std::cout.tie(0);
int T = 1;
std::cin >> T;
while (T--) dickdreamer();
// std::cerr << 1.0 * clock() / CLOCKS_PER_SEC << "s\n";
return 0;
}

CF1698F Equal Reversal 题解
https://sobaliuziao.github.io/2025/09/18/post/6ee84d88.html
作者
Egg_laying_master
发布于
2025年9月18日
许可协议