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 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步