White Magic
题目链接
题意:
一个序列被称为“魔法”的,如果对于序列中的每一个元素(除了最后一个),它和它之前的所有元素的最小值大于或等于它后面所有元素的MEX值。这里的MEX是指不在一个集合中出现的最小非负整数。找到给定序列的最大“魔法”子序列长度。
思路:
首先,一个“魔法”序列中最多存在一个零,因为如果存在两个以上的零,那么对于第一个零来说,它和它之前所有元素的最小值为0,而它后面所有元素的MEX值肯定大于0,不符合。对于一个没有零的序列,它一定是“魔法”序列。所以进行分类讨论,当序列没有0时,答案就是序列的长度;当序列只有一个0时,答案可能为n,可能为n-1,取决与那个0是否可以存在;当序列有多个0时,肯定最多留一个0,我们可以先留一个0,其余0全部删去,这样就和第二种情况一样了,这时,我们只需考虑留哪一个0更好,可以证明留最左边的零最优。最后来到如何判断一个含1个0的序列是否为“魔法”序列,我们可以用统计前缀最小值和后缀mex值。具体实现见代码。
点击查看代码
// #pragma GCC optimize("O3")
// #pragma G++ optimize("O3")
#include <bits/stdc++.h>
using namespace std;
#define endl '\n'
#define int long long
#define ll long long
const int N = 2e5+5;
int arr[N];
int mex[N];
map<int,int>mp;
void solve(){
int n;
cin>>n;
mp.clear();
int g=0;
for(int i=1;i<=n;++i){
cin>>arr[i];
if(arr[i]==0){
g++;
}
}
if(n==1){
cout<<1<<endl;
return ;
}
if(g==0){
if(n<=0) n=1;
cout<<n<<endl;
return ;
}
vector<int>v;
if(g>1){
int x=0;
for(int i=1;i<=n;++i){
if(arr[i]==0){
if(x){
}else{
v.push_back(arr[i]);
}
x++;
}else{
v.push_back(arr[i]);
}
}
n=v.size();
for(int i=0;i<n;++i){
arr[i+1]=v[i];
}
}
if(arr[n]==0){
mex[n]=1;
}else{
mex[n]=0;
mp[arr[n]]++;
}
for(int i=n-1;i>0;--i){
if(arr[i]!=mex[i+1]){
mex[i]=mex[i+1];
mp[arr[i]]++;
}else{
for(int j=mex[i+1]+1;;++j){
if(mp[j]){
}else{
mex[i]=j;
break;
}
}
}
}
int zuixiao=arr[1];
if(zuixiao>=mex[2]){
}else{
if(n-1<=0) n=2;
cout<<n-1<<endl;;
return ;
}
for(int i=2;i<n;++i){
zuixiao=min(zuixiao,arr[i]);
if(zuixiao>=mex[i+1]){
}else{
if(n-1<=0) n=2;
cout<<n-1<<endl;
return ;
}
}
if(n<=0) n=1;
cout<<n<<endl;
return ;
}
signed main(){
ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
int _=1;
cin>>_;
while(_--)
solve();
return 0;
}

浙公网安备 33010602011771号