题解:P14134 【MX-X22-T5】「TPOI-4E」Get MiN? Get MeX!

· · 题解

简单题?

10pts

我们把 1\sim n 都扫一遍,其中会有两个值为 1 的位置,用 2 类询问判断一下就好了

25pts

首先我们不难发现,将一个序列从中间劈开,左右两边的 min+mex 的值是相等的,所以我们考虑维护两个区间,每次将每个区间砍半,询问这 4 个区间,我们发现必然有两个区间的值相等,且这两个值必然是 4 区间的值中的最小值,同时 01 在这两个区间内,证明不难留给读者自行思考。那么每次就可以将区间大小缩小一半,询问次数为 O(4\log_2 n)。最后找出两个值为 1 的点后用 10pts 的方法判断就好了。

40pts

容易想到 4 个区间中有一个询问是没有必要的,询问次数为 O(3\log_2 n)

100pts

我们这个 \log n 是降不下来的,于是考虑怎么每次用 2 次询问就可以缩小范围。假设当前的两个区间为 [l_1,r_1],[l_2,r_2],他们询问出的值为 x,两个区间的中点为 m_1,m_2,区间 [l_1,m_1],(m_1,r_1],[l_2,m_2],(m_2,r_2] 询问出的值为 a,b,c,dy=\min(a,b,c,d),那么 y\le x

同时我们有当 a=bc=dy<x,当 a=ca=db=cb=dy=x

证明不难。

由于 a=b 或者 c=d 同理,所以我们只考虑 a=b

假设 0[l_1,m_1] 区间内,那么 \min[l_1,m_1]=0\operatorname{mex}[l_1,m_1]=a,此时由于 a=b 所以 \min (m_1,r_1]=a\operatorname{mex}(m_1,r_1]=0

我们发现,此时在区间 [l_1,r_1]0 \sim a 都存在,那么 \min[l_1,r_1]=0\operatorname{mex}[l_1,r_1]=a+1,即 x=a+1,也即 y<x

由于 $a=c$ 或 $a=d$ 或 $b=c$ 或 $b=d$ 也同理,所以我们也只考虑 $a=c$。同样,我们假设 $0$ 在区间 $[l_1,m_1]$ 内,那么 $\min[l_1,m_1]=0$ 且 $\operatorname{mex}[l_1,m_1]=a$,此时由于 $a=c$ 所以 $\min[l_2,m_2]=a$ 且 $\operatorname{mex}[l_2,m_2]=0$。 我们知道,因为 $\min[l_2,m_2]=a$,所以 $a$ 一定在 $[l_2,m_2]$ 中,那么 $a$ 就一定不在 $(m_1,r_1]$ 中,因此 $\operatorname{mex}[l_1,r_1]$ 一定等于 $a$,同时根据 25pts 中的结论可以得到 $\min[l_2,r_2]=a$,此时 $x=a$,即 $x=y$。 $0$ 在 $[l_2,m_2]$ 区间内同理。 现在我们考虑询问出 $a,d$,那么有一下几种情况: 1. $a=d$:这个直接选 $a,d$; 2. $a>x,d>x$:直接选 $b,c$; 3. $a=x,d>x$:选择 $a,c$; 4. $a>x,d=x$:同理,选择 $b,d$; 5. $a<x$:选择 $a,b$; 6. $d<x$:同理,选择 $c,d$; 7. $a<x,d<x$:可以证明这种情况不存在。 由于区间每次会缩小一半,所以最多会缩小 $\log n$ 次,同时每次缩小使用 $2$ 次询问,加上开始时询问的一次,总共 $2 \log_2 n+1$ 次,在 $n \le 10^5$ 时最多为 $35$ 次。 最后当区间缩小为两个点时,两个点必然一个为 $1$ 一个为 $0$,直接用 10pts 的方法判断一下就做完了。 ```c++ //by CuteLord uid:1114894 #include<bits/stdc++.h> using namespace std; int n; int query(int l,int r,int op=0){ /* 询问就不给了 */ } int l1,r1; int l2,r2; int main(){ cin>>n; l1=1,r1=n+1>>1; l2=r1+1,r2=n; int last=query(l1,r1); while(1){ int m1=l1+r1>>1,m2=l2+r2>>1; int a=query(l1,m1); int b=query(m2+1,r2); if(a==b){ r1=m1; l2=m2+1; last=a; }else if(a>last&&b>last){ l1=m1+1; r2=m2; }else if(a<last){ l2=m1+1,r2=r1; r1=m1; last=a; }else if(b<last){ l1=l2,r1=m2; l2=m2+1; last=b; }else if(a==last&&b>last){ r1=m1; r2=m2; }else if(b==last&&a>last){ l1=m1+1; l2=m2+1; } if(l1==r1&&l2==r2)break; else if(l1==r1){ m2=l2+r2>>1; a=query(l2,m2); b=query(m2+1,r2); if(a<b)r2=m2; else l2=m2+1; break; }else if(l2==r2){ m1=l1+r1>>1; a=query(l1,m1); b=query(m1+1,r1); if(a<b)r1=m1; else l1=m1+1; break; } } if(query(l1,l1,1)<0)cout<<"! "<<l1; else cout<<"! "<<l2; } ```