题解:CF2049E Broken Queries
思路
大力分讨。
下文称对区间
设
考虑将数组分为
设第
接下来进行分类讨论:
若 $val_3=1$,说明 $k>n-mid_1$,那么在 $[1,mid_1]$ 中找到一个最大的 $g$ 使得区间 $[g,n]$ 的检验值为 $0$,此时 $k=n-g+1$。 否则,在 $[1,mid_1]$ 中找到一个最小的 $g$ 使得区间 $[1,g]$ 的检验值为 $1$,此时 $k=g$。 $val_1\not=val_2$,此时 $1$ 不在第三部分内。 若 $val_3=0$,说明 $k>n-mid_1$,那么在 $[mid_1+1,n]$ 中找到一个最小的 $g$ 使得区间 $[1,g]$ 的检验值为 $0$,此时 $k=g$。 否则,在 $[mid_1+1,n]$ 中找到一个最大的 $g$ 使得区间 $[g,n]$ 的检验值为 $1$,此时 $k=n-g+1$。
Code
#include<bits/stdc++.h>
using namespace std;
#define int long long
#define pii pair<int,int>
#define fi first
#define se second
#define mp make_pair
#define debug1(x) cerr<<#x<<"="<<x<<" "
#define debug2(x) cerr<<#x<<"="<<x<<"\n"
const int inf=1e16;
int check(int l,int r){
cout<<"? "<<l<<" "<<r<<endl;
int pos;cin>>pos;
return pos;
}
signed main(){
// ios::sync_with_stdio(0);
// cin.tie(0);
int t;cin>>t;
while(t--){
int n;cin>>n;
int mid1=n/2,mid2=mid1/2;
int val1=check(1,mid2),val2=check(mid2+1,mid1),val3=check(mid1+1,n);
int g=0,l=0,r=0,k=0;
if(val1==val2){
l=1;r=mid1;
if(val3){
while(l<=r){
int mid=(l+r)/2;
if(check(mid,n)==0)g=mid,l=mid+1;
else r=mid-1;
}
k=n-g+1;
}
else{
while(l<=r){
int mid=(l+r)/2;
if(check(1,mid)==1)g=mid,r=mid-1;
else l=mid+1;
}
k=g;
}
}
else{
l=mid1+1;r=n;
if(val3){
while(l<=r){
int mid=(l+r)/2;
if(check(mid,n)==1)g=mid,l=mid+1;
else r=mid-1;
}
k=n-g+1;
}
else{
while(l<=r){
int mid=(l+r)/2;
if(check(1,mid)==0)g=mid,r=mid-1;
else l=mid+1;
}
k=g;
}
}
cout<<"! "<<k<<endl;
}
return 0;
}