题目描述
难度分:1300
输入T(≤104)表示T组数据。所有数据的n之和≤2×105。
每组数据输入n(1≤n≤2×105)和长为n的数组a(−109≤a[i]≤109),长为n的字符串s,仅包含B
和R
。
每次操作,你可以选择一个下标i。
如果s[i]=B
,把a[i]减少1。
如果s[i]=R
,把a[i]增加1。
能否在执行若干次(或者零次)操作后,把数组a变成一个1到n的排列?
输出YES
或NO
。
输入样例
8
4
1 2 5 2
BRBR
2
1 1
BB
5
3 1 4 2 5
RBRRB
5
3 1 3 1 3
RBRRB
5
5 1 5 1 5
RBRRB
4
2 2 2 2
BRBR
2
1 -2
BR
4
-2 -1 4 0
RRRR
输出样例
YES
NO
YES
YES
NO
YES
YES
YES
算法
贪心
假设B
位置的元素有b个,R
位置的元素有r个。比较容易想到的一种构造方案就是,让所有B
的元素构成排列的前b项,所有R
的元素构成排列的后r项。因此,将所有B
和R
位置的元素a[i]分别存入到dec和inc两个数组中并排序,按照顺序来构建1到n的排列。
在构造的过程中需要满足:inc中的元素不能太大,即inc[i]>b+i+1时不合法(i从0开始)。dec中的元素不能太小,即dec[i]<i+1时不合法。
复杂度分析
时间复杂度
遍历一遍s串构建inc和dec两个数组,时间复杂度为O(n)。对inc和dec排序,时间复杂度为O(nlog2n)。最后遍历这两个有序数组进行验证,时间复杂度为O(n)。综上,整个算法的时间复杂度为O(nlog2n)。
空间复杂度
排序的空间复杂度为O(log2n)(快速排序),但瓶颈在于inc和dec两个数组,两个数组加起来的空间复杂度为O(n)。因此,整个算法的额外空间复杂度为O(n)。
C++ 代码
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
const int N = 200010;
int T, n, a[N];
char s[N];
bool solve() {
vector<int> dec, inc;
for(int i = 1; i <= n; i++) {
if(s[i] == 'B') {
dec.push_back(a[i]);
}else {
inc.push_back(a[i]);
}
}
sort(inc.begin(), inc.end());
sort(dec.begin(), dec.end());
for(int i = 0; i < dec.size(); i++) {
if(dec[i] < i + 1) return false;
}
int offset = dec.size();
for(int i = 0; i < inc.size(); i++) {
if(inc[i] > offset + i + 1) return false;
}
return true;
}
int main() {
scanf("%d", &T);
while(T--) {
scanf("%d", &n);
for(int i = 1; i <= n; i++) {
scanf("%d", &a[i]);
}
scanf("%s", s + 1);
bool flag = solve();
if(flag) puts("YES");
else puts("NO");
}
return 0;
}