Codeforces-1607 D: Blue-Red Permutation
题目
题目传送门:codeforces 1607D
题目截图
样例描述
题目大意
给定一个序列 { a i } \{a_i\} {ai},序列的每个元素拥有颜色,要么是 B B B 颜色,要么是 R R R 颜色。对于 B B B 颜色的元素 a i a_i ai,可以将其调整为任意 ≤ a i \le a_i ≤ai的值,而对于 R R R 颜色的元素 a i a_i ai ,可以将其调整为任意 ≥ a i \ge a_i ≥ai的值。问,能否将该序列调整为一个排列(排列指长度为 n n n 的序列,以任意顺序包含 1 ⋯ n 1 \cdots n 1⋯n 的所有元素,且所有元素只出现一次)。
题目解析
如果我们将
B
B
B 与
R
R
R 分开讨论,很容易想到,它们在各自情况下,按数值从小到大排序(本文将这个方向称作向右)去依次分配
1
⋯
n
1 \cdots n
1⋯n (本文将这一操作称作依次赋值)是最好的。
考虑把
B
B
B 和
R
R
R 放一起的情况,可以假设目前我们已经有了一个已经排好了的情况,如果存在
R
R
R 中有一个数值
x
∈
[
1
,
n
]
x \in [1, n]
x∈[1,n] ,从
B
B
B 中有一个数值
y
∈
[
1
,
n
]
y \in [1, n]
y∈[1,n] ,当
x
<
y
x < y
x<y 时,若将
R
R
R 中数值
x
x
x 变为
x
+
(
y
−
x
)
=
y
x + (y - x)=y
x+(y−x)=y,将
B
B
B 中数值
y
y
y 变为
y
−
(
y
−
x
)
=
y
y - (y - x)=y
y−(y−x)=y,那么两者的值就可以互换了(因为
R
R
R 的元素可以无限向上调整,
B
B
B的元素可以无限向下调整)。即是说,如果把答案所有的
R
R
R 元素在不改变
R
R
R 元素相对位置的情况下,可以不断与右边的
B
B
B 元素互换位置。最终,可以发现任何符合条件的结果,都可以变换成左边都是
B
B
B 元素,右边都是
R
R
R 元素的情况。如此一来我们分开将
B
、
R
B、R
B、R 从小到大排序,贪心地顺序从两个序列依次选取元素赋值即可。
换个更简单的思考方式,由于
B
B
B 有上界,随
1
⋯
n
1 \cdots n
1⋯n 的增加,我们可以依次先选取
B
B
B 中的元素赋值,遇到不行的情况时,再从小到大选取
R
R
R 中的元素赋值补上(经典贪心)。上段只是说明,若能够形成排列,一旦遇到
B
B
B 不行的情况,后面的全是
R
R
R 元素了。
Code
#include <bits/stdc++.h>
using namespace std;
const int maxn = 2e5 + 7;
int a[maxn];
vector<int> B, R;
int main(){
int t, n;
string sa;
cin >> t;
while (t--) {
B.clear(); R.clear();
cin >> n;
for(int i=0; i<n; ++i) cin >> a[i];
cin >> sa;
for(int i=0; i<n; ++i)
if (sa[i] == 'B') B.push_back(a[i]); else R.push_back(a[i]);
sort(B.begin(), B.end());
sort(R.begin(), R.end());
int ptrB = 0, ptrR = 0;
bool fl = true;
for(int k=1; k<=n; ++k) {
if (ptrB<B.size() && B[ptrB] >= k) ++ptrB; else
if (ptrR<R.size() && R[ptrR] <= k) ++ptrR; else {
fl = false;
break;
}
}
if (fl) cout << "YES" << endl;
else cout << "NO" << endl;
}
return 0;
}