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;
}
posted @ 2023-09-05 20:07  monster_hunterqwq  阅读(34)  评论(0编辑  收藏  举报  来源