题目
给你长度为N数组,
每个元素都具有一种颜色,一共有两种颜色,蓝色使这个元素能自我减少,红色使这个元素能自我变大。
要求判断数组N能否成为1—N的序列。
例如N= 4
1 3 4 2
1 2 3 4
题解思路
将每个元素看成一个区间,蓝色赋为1-a[i],红色赋为a[i]-N。
将区间左右端点都从小到大排序。
再从小到大判断1-N的数。看看是否每个数都有区间能放下它。
这样看起来是对的思路。
实际上需要特判负数。
元素为负数的时候,如果为蓝色,这个数组必然不能变成序列,红色时,这个元素可以变成1-n的所有数。我们把它变成超级区间,特殊处理(在判断的时候,如果没有区间满足就让超级区间来顶替)。
其他人的思路好像没那么多特判,将蓝色和红色分开考虑并排序,直接先全用蓝色,再用红色。
用蓝色的时候只需考虑右端点够不够大。红色的时候考虑左端点够不够小。(基于贪心)
AC代码
#include <bits/stdc++.h>
//#include <unordered_map>
#define PII pair<int,int>
#define ll long long
using namespace std;
const int INF = 0x3f3f3f3f;
const int N = 200100 ;
int a[N] ;
int n ;
struct node
{
int x , y ;
};
bool cmp (node A , node B )
{
if ( A.x == B.x )
return A.y < B .y ;
return A .x < B.x ;
}
int main()
{
ios::sync_with_stdio(false);cin.tie(0);
int T ;
cin >> T ;
while( T-- )
{
vector < node > h ;
int pit = 0 ;
string s ;
cin >> n ;
for (int i = 0 ; i < n ; i++ )
cin >> a[i] ;
cin >> s ;
bool flag = 1 ;
for (int i = 0 ; i < n ; i++ )
{
if (s[i] == 'B' )
{
if (a[i] < 1 )
flag = 0 ;
h.push_back({1,a[i]});
}else
{
if (a[i]>0)
h.push_back({a[i],n});
else
pit ++ ;
}
}
sort(h.begin(),h.end(),cmp) ;
int tag = 0 ;
for (int i = 0 ; i < h.size() ; i++ )
{
if (h[i].x > tag + 1 || h[i].y < tag + 1 )
{
if (pit)
{
pit--;
i--;
}else
{
flag = 0 ;
break ;
}
}
tag++ ;
}
if (flag)
cout << "YES\n";
else
cout << "NO\n" ;
}
return 0 ;
}