挺简单的交互题。不知道为什么这题在 cf 上的版本 评了 *2700。并且有双倍经验。
首先显然是要二分答案然后用交互 check 的。我们先尝试从 开始是否可行。容易发现,如果得到 , 此时原本在 左右,而第二次我们要找到一个 使得 。这显然是无解的。
不过这也启示我们应该从每次跳的距离都最大的情况去考虑,如何找到一个合法的起点。
因为极端情况下 不断变大,于是倒序考虑,先确定终点在 ,处理出每次的 ,在数轴上考虑,每次先往右再往左跳。跳完所有的 时在的位置就是我们要的起点。
此时就会有一个问题:会不会向左/右的空间不够导致奇怪的 的重复呢?其实是不会的,因为容易发现每次就相当于把一个区间不断缩小,直到区间长度 。
于是我们就可以想出这么一种构造:从这个起点开始,二分同时依次向左向右跳(根据上面处理起点时的相反顺序来)。
然后又有一个问题了:这样会不会重复?感性理解一下是不会的,有具体证明可以敲敲我。
code:
ll n,m,a[107];
il ll ask(ll x,int op){
if(op){
printf("= %lld\n",x);
fflush(stdout);
return 0;
}
printf("? %lld\n",x);
fflush(stdout);
ll y;scanf("%lld",&y);
return y;
}
void Yorushika(){
scanf("%lld",&n),m=0;
ll l=1,r=n-1;
while(l<=r){
ll mid=(l+r)>>1;
a[++m]=mid,l=mid+1;
}
reverse(a+1,a+m+1);
ll p=1;
rep(i,1,m){
if(i&1){
p+=a[i];
}else{
p-=a[i];
}
}
ll x=ask(p,0);
l=1,r=n-1;
ll ans=n,cnt=0;
while(l<=r){
ll mid=(l+r)>>1;
cnt++;
if(abs(m-cnt)&1){
x=ask(p+=mid,0);
}else{
x=ask(p-=mid,0);
}
if(x){
ans=mid;
r=mid-1;
}else{
l=mid+1;
}
}
ask(ans,1);
}
signed main(){
int t=1;
scanf("%d",&t);
while(t--)
Yorushika();
}