Codeforces-1672 D: Cyclic Rotation
题目链接:Codeforces-1672 D
题目
题目截图
样例描述
题目大意
给定一个数组长度
n
n
n,并给定数组
a
a
a。
可以对
a
a
a 数组实行一个操作,选择两个下标
l
,
r
for
1
≤
l
≤
r
≤
n
a
n
d
a
l
=
a
r
l, r \; \text{for}\; 1 \le l \le r \le n \; and \; a_l=a_r
l,rfor1≤l≤r≤nandal=ar,将
a
l
a_l
al 放到
a
r
a_r
ar 的后面,此时
a
[
l
⋯
r
]
=
[
a
l
+
1
,
a
l
+
2
,
⋯
,
a
r
,
a
l
]
a[l\cdots r]=[a_{l+1},a_{l+2},\cdots,a_r,a_l]
a[l⋯r]=[al+1,al+2,⋯,ar,al]。
现在给出另一个数组
b
b
b。问数组
a
a
a 能否通过变换,变为数组
b
b
b。(数据保证
b
b
b 是
a
a
a 的重排列)
题目解析
我们将这个过程反过来想,对
a
a
a 数组的操作的反过程 相当于 在
b
b
b 数组中选择两个连续且值相同的位置
i
,
i
+
1
;
b
[
i
]
=
b
[
i
+
1
]
i,i+1;b[i]=b[i+1]
i,i+1;b[i]=b[i+1],且将
b
[
i
+
1
]
b[i+1]
b[i+1] 替换到
i
i
i 之前的某个位置。
那么,如果我们能够使用双指针法,在两个数组中分别反过来遍历:当
b
[
i
]
=
b
[
i
+
1
]
b[i] = b[i+1]
b[i]=b[i+1] 时,我们将
b
[
i
+
1
]
b[i+1]
b[i+1] 储存起来,以便
b
j
b_j
bj 与
a
i
a_i
ai 不相等时,取出储存的数放入,就能够从
b
b
b 数组恢复为
a
a
a 数组。值得注意的是当
b
b
b 中有很多个数连续相等的话,只取两个数
b
[
i
]
,
b
[
i
+
1
]
b[i],b[i+1]
b[i],b[i+1] 可能是不行的(对应下面代码中 while -> if 的情况),因为理论上整个连续相等的段,除了首元素,都可以被储存起来,如果只储存最后一位,之后就开始比较,就会浪费储存的机会,导致有时候找不到
a
a
a 中某个元素的对应值。例如
a
=
[
2
,
2
,
1
,
2
]
,
b
=
[
1
,
2
,
2
,
2
]
a=[2, 2, 1, 2], b=[1,2,2,2]
a=[2,2,1,2],b=[1,2,2,2],理论上可以从
a
a
a 变为
b
b
b,但若只存最后一个,判断就会变为不行。因此,要最大程度地利用储存插入这一性质。
Code
#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 7;
int a[maxn], b[maxn], cnt[maxn];
int main() {
int t, n;
cin >> t;
while(t--) {
cin >> n;
for(int i=1; i<=n; ++i) cin >> a[i];
for(int i=1; i<=n; ++i) cin >> b[i];
for(int i=1; i<=n; ++i) cnt[i] = 0;
bool fl = true;
for(int i=n, j=n; i>=1; --i) {
while(j>1 && b[j] == b[j-1]) ++cnt[b[j]], --j;
if(j>=1 && a[i] == b[j]) --j; else
if(cnt[a[i]] > 0) --cnt[a[i]]; else {
fl = false;
cout << "NO" << endl;
break;
}
}
if(fl) cout << "YES" << endl;
}
return 0;
}