CF1870E Another MEX Problem 题解
注意题中取出来的区间的并不一定恰好是整个序列。
思路
一个比较重要而且比较经典的结论是:序列的极短 mex 区间个数是 \(O(n)\) 的。这里的极短 mex 区间是指满足对于区间 \([l,r]\),有 \(\text{mex}(l,r)\ne \text{mex}(l+1,r)\wedge \text{mex}(l,r)\ne \text{mex}(l,r-1)\),也就是区间的所有真子区间的 \(\text{mex}\) 都与当前区间的 \(\text{mex}\) 不同的区间。
证明是比较简单的,考虑钦定 \(a_l<a_r\)(显然有 \(a_l\ne a_r\))。
第一个比较显然的观察是 \(\text{mex}(l,r)>a_r>a_l\),否则我们就可以将 \(a_r\) 去掉使得 \(\text{mex}\) 不变。
考虑一个 \(a_{l'},l'<l\),我们想要去证明 \([l',r]\) 不可能是一个极短 mex 区间。如果得证那么就意味着对于每一个右端点,都至多有一个 \(a_l<a_r\) 使得 \([l,r]\) 是极短 mex 区间。
事实上比较容易。因为一定有 \(\text{mex}(l',r) \ge \text{mex}(l,r)>a_r>a_{l'}\),也就是说 \(a_{l'}\) 已经在 \([l,r]\) 中出现过了,因此 \([l',r]\) 不是极短 mex 区间,原问题得证。
然后对于 \(a_l>a_r\) 有类似的分析,将两个结论拼在一起就有了最开始的那个结论。
有了那个结论后,就可以回到这道题上来了。由于一个极短 mex 区间一定不劣于包含它且 mex 与其相同的区间,因此我们只需要从这些极短 mex 区间转移即可。
设 \(f_{i,j}\) 表示所有选了的区间右端点小于等于 \(i\)(注意没有钦定 \(i\) 必须选),是否能够表示出 \(j\)。
转移就比较简单了,我们将极短 mex 区间挂在右端点上扫描线即可。具体的,
其中 \(S\) 是极短 mex 区间的集合。求 \(S\) 用暴力的扫描线即可。
code
比较好写。注意空间。
点击查看代码
#include<bits/stdc++.h>
bool Mbe;
using namespace std;
#define ll long long
//namespace FIO{
// template<typename P>
// inline void read(P &x){P res=0,f=1;char ch=getchar();while(ch<'0' || ch>'9'){if(ch=='-') f=-1;ch=getchar();}while(ch>='0' && ch<='9'){res=(res<<3)+(res<<1)+(ch^48);ch=getchar();}x=res*f;}
// template<typename Ty,typename ...Args>
// inline void read(Ty &x,Args &...args) {read(x);read(args...);}
// inline void write(ll x) {if(x<0ll)putchar('-'),x=-x;static int sta[35];int top = 0;do {sta[top++] = x % 10ll, x /= 10ll;} while (x);while (top) putchar(sta[--top] + 48);}
//}
//using FIO::read;using FIO::write;
const int N=5007;
int a[N],n,vis[N],g[N][N];
bool f[N][N<<1];
struct node{int l,mex;};
vector <node> q[N];
void solve(){
cin>>n;for(int i=1;i<=n;i++){cin>>a[i];}
for(int r=1;r<=n;r++){
int mx=0;
for(int l=r;l>=1;l--){vis[a[l]]=1;while(vis[mx])mx++;g[l][r]=mx;}
for(int l=1;l<=r;l++){vis[a[l]]=0;}
}
for(int r=1;r<=n;r++){for(int l=r;l>=1;l--){if(g[l][r]!=g[l+1][r]&&g[l][r]!=g[l][r-1])q[r].push_back({l,g[l][r]});}} //即使 l=r 也无妨
f[0][0]=1;
for(int r=1;r<=n;r++){
for(int i=0;i<=5000;i++)f[r][i]=f[r-1][i];
for(auto [l,w]:q[r]){for(int i=0;i<=5000;i++)f[r][i]|=f[l-1][i^w];}
vector<node>().swap(q[r]);
}
int ans=0;
for(int i=0;i<=5000;i++)if(f[n][i])ans=i;
cout<<ans<<'\n';
}
void init(){for(int i=1;i<=n;i++)for(int j=0;j<=5000;j++)f[i][j]=0;for(int i=1;i<=n;i++)for(int j=i;j<=n;j++)g[i][j]=0;}
bool Med;
signed main(){
ios::sync_with_stdio(false),cin.tie(0),cout.tie(0);
//freopen(".in","r",stdin);
//freopen(".out","w",stdout);
int T;cin>>T;while(T--)solve(),init();
cerr<<'\n'<<1e3*clock()/CLOCKS_PER_SEC<<"ms\n";
cerr<<'\n'<<fabs(&Med-&Mbe)/1048576.0<<"MB\n";
return 0;
}

浙公网安备 33010602011771号