P7345题解
题意
给一个点 $s$ 和最多 $MAX$ 次询问,同时给出一个与该点的 Manhattan 距离为 $t$ 的点,每次可询问一个点,如果与 $s$ 的 Manhattan 距离小于等于 $t$ 则返回 $1$,否则返回 $0$,求 $s$ 的坐标。
题解
众所周知,交互题的询问次数基本上都是卡死的,所以我们可以从最大次数去反向分析。
我们发现,题目中给的 $MAX$ 由前后两部分组成。
似乎后半部分的 $2$ 挺好处理的,那就先看看 $2$ 能做什么。
下面是一张 $t=5$ 时的图 ,显然是正方形。
可以发现,两步能确定这个点所在的是正方形的哪条边(假设顶点可以属于任意一条边)
接下来观察前半部分。
$\left\lceil\log_2{t+1}\right\rceil$
$\log_2$ 提示我们思考二分。
则可以想到在已知点属于哪条边的情况下,可以二分查找点关于正方形两顶点连线(图中即为 $x$ 轴)的对称点。
如果以两点之间距离为二分对象,则询问次数为 $\left\lceil\log_2{2\times t +1}\right\rceil $,显然无法通过。
考虑改变二分对象。以正方形长度为二分对象,则询问次数减少为 $\left\lceil\log_2t+1\right\rceil$,恰好与 $MAX$相等。
根据得到的长度计算即可。
code
#include <bits/stdc++.h>
#define f fflush(stdout)
using namespace std;
int n,i,j,k,m,t,useless,num1,num2,tmp,x,y,ans;
int l,r;
int main() {
scanf("%d",&t);
while(t--){
scanf("%d%d%d%d",&n,&x,&y,&useless);
printf("0 %d %d\n",x,y-1);
f;
scanf("%d",&num1);
printf("0 %d %d\n",x-1,y);
f;
scanf("%d",&num2);
if(num1==1){
l=1,r=n+1;
while(l<r){
int mid=(l+r)>>1;
printf("0 %d %d\n",x,y-2*mid+1);
f;
scanf("%d",&tmp);
if(tmp==0) r=mid;
else l=mid+1;
}
ans=r-1;
if(num2==0) printf("1 %d %d\n",x+(n-ans),y-ans);
else printf("1 %d %d\n",x-(n-ans),y-ans);
f;
}
else{
l=1,r=n+1;
while(l<r){
int mid=(l+r)>>1;
printf("0 %d %d\n",x,y+2*mid-1);
f;
scanf("%d",&tmp);
if(tmp==0) r=mid;
else l=mid+1;
}
ans=r-1;
if(num2==0) printf("1 %d %d\n",x+(n-ans),y+ans);
else printf("1 %d %d\n",x-(n-ans),y+ans);
f;
}
}
return 0;
}