CF2067E - White Magic

题面

  • 首先发现,对于一个没有 0 的序列,神奇序列最大长度为 n,因为对于任意一个后缀,其 mex 恒为 0,而对应前缀 min 始终大于零。

  • 对于一个选择的子序列,如果序列中存在两个 0,其一定不满足条件,因为存在一个只包含一个 0 的后缀,其 mex 不为 0,而对应前缀 min 一定为 0。

  • 所以,对于对于一个最长合法子序列,其一定包含所有非 0 的数,可能还会再包含一个 0。

  • 那么我们该选择哪个 0 加到最长合法子序列呢?通过贪心,我们只需选择序列最左边的 0 进行检验,证明:如果 0 在子序列的位置越靠右,那么当后缀包括 0 后,其 mex 一定不比在左边时小,其前缀 min 一定不会更大。

  • 所以我们只需对序列最左边的 0 检验即可,用 O(n) 的时间判断每个前缀 min 和后缀 mex 的大小关系即可。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const ll N=2e5+5,inf=1e16;
ll n,a[N],b[N],s[N];
bool c[N];
ll sol(){
	cin>>n;
	bool fla=1;
	ll m=0,cnt;
	for(int i=1;i<=n;i++){
		cin>>a[i];
		if(a[i]==0){
			if(fla)b[++m]=a[i];
			fla=0;
		}else b[++m]=a[i];
	}
	if(fla)return n;
	s[0]=inf;
	for(int i=1;i<=m;i++){
		s[i]=min(s[i-1],b[i]);
	}
	ll p=0;
	for(int i=m;i>=1;i--){
		if(b[i]<N)c[b[i]]=1;
		while(c[p])p++;
		if(s[i-1]<p)fla=1;
	}
	for(int i=1;i<=m;i++){
		if(b[i]<N)c[b[i]]=0;
	}
	if(fla)return m-1;
	else return m;
}
int main(){
	ios::sync_with_stdio(0),cin.tie(0),cout.tie(0);
	int T;
	cin>>T;
	while(T--)cout<<sol()<<'\n';
}

本文作者:Exotic-sum

本文链接:https://www.cnblogs.com/Exotic-sum/p/18718754

版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。

posted @   xzhiflow  阅读(3)  评论(1编辑  收藏  举报
点击右上角即可分享
微信分享提示
评论
收藏
关注
推荐
深色
回顶
收起